Oto podejście względnie wolne od płyt przy użyciu metody bezkształtnej. Najpierw musimy zdefiniować kilka polimorficzne wersje odpowiednich funkcji na Option
:
import shapeless._
object orElser extends Poly1 {
implicit def default[A] = at[Option[A]] {
oa => (o: Option[A]) => oa orElse o
}
}
object getOrElser extends Poly1 {
implicit def default[A] = at[Option[A]] {
oa => (a: A) => oa getOrElse a
}
}
Będziemy reprezentować aktualizacji jako HList
gdzie każdy element jest Option
i możemy napisać metodę append
która pozwala nam dołączyć dwie aktualizacje :
import UnaryTCConstraint._
def append[U <: HList: *->*[Option]#λ, F <: HList](u: U, v: U)(implicit
mapper: MapperAux[orElser.type, U, F],
zipper: ZipApplyAux[F, U, U]
): U = v.map(orElser).zipApply(u)
I wreszcie możemy napisać nasz update
samą metodę:
def update[T, L <: HList, F <: HList, U <: HList](t: T, u: U)(implicit
iso: Iso[T, L],
mapped: MappedAux[L, Option, U],
mapper: MapperAux[getOrElser.type, U, F],
zipper: ZipApplyAux[F, L, L]
) = iso from u.map(getOrElser).zipApply(iso to t)
Teraz musimy tylko trochę boilerplate (w the future to nie będzie konieczne, dzięki inference-driving macros):
implicit def pcIso =
Iso.hlist(PropositionContent.apply _, PropositionContent.unapply _)
Będziemy również zdefiniować alias dla tego konkretnego typu aktualizacji (co nie jest bezwzględnie konieczne, ale sprawi, że poniższe przykłady trochę bardziej zwięzłe):
type PCUpdate = Option[String] :: Option[String] :: HNil
I wreszcie:
scala> val pc = PropositionContent("some title", "some content")
pc: PropositionContent = PropositionContent(some title,some content)
scala> val u1: PCUpdate = Some("another title") :: None :: HNil
u1: PCUpdate = Some(another title) :: None :: HNil
scala> val u2: PCUpdate = Some("newest title") :: Some("new content") :: HNil
u2: PCUpdate = Some(newest title) :: Some(new content) :: HNil
scala> append(u1, u2)
res0: PCUpdate = Some(newest title) :: Some(new content) :: HNil
scala> update(pc, append(u1, u2))
res1: PropositionContent = PropositionContent(newest title,new content)
który jest w Kapelusz, który chcieliśmy.
wskazówka: https://blog.stackmob.com/2012/02/an-introduction-to-lenses-in-scalaz/ –
co z aliasami typów? – sschaef
masz na myśli 'type CompleteProposistionContent = PropositionContent [Id]'? – jwinandy