このような具体的なタスクの場合、map
にPoly
のようなものを入力するよりも、しばしば型クラスを作成する方が簡単です。
次のように我々はいくつかのT
にアップデートを表現することができます
trait Update[T] {
def apply(base: T, update: T): T
}
は、今、私たちはいくつかのインスタンスを定義する必要があります。 List
とOption
といくつかのインスタンスを更新してUpdate[Foo]
インスタンスを派生させる方法
import shapeless._
object Update extends Update0 {
def apply[A](implicit update: Lazy[Update[A]]): Update[A] = update.value
implicit def optionUpdate[A]: Update[Option[A]] =
new Update[Option[A]] {
def apply(base: Option[A], update: Option[A]): Option[A] = update orElse base
}
implicit def listUpdate[A]: Update[List[A]] =
new Update[List[A]] {
def apply(base: List[A], update: List[A]): List[A] = base ++ update
}
implicit def hnilUpdate: Update[HNil] =
new Update[HNil] {
def apply(base: HNil, update: HNil): HNil = HNil
}
implicit def hconsUpdate[H, T <: HList](
implicit updateH: Update[H], updateT: Lazy[Update[T]]
): Update[H :: T] =
new Update[H :: T] {
def apply(base: H :: T, update: H :: T): H :: T =
updateH(base.head, update.head) :: updateT.value(base.tail, update.tail)
}
}
trait Update0 {
implicit def genericUpdate[A, G <: HList](
implicit gen: Generic.Aux[A, G], updateG: Lazy[Update[G]]
): Update[A] =
new Update[A] {
def apply(base: A, update: A): A =
gen.from(updateG.value(gen.to(base), gen.to(update)))
}
}
我々はそれが少し容易にするために、いくつかの構文を追加することができます。
implicit class UpdateOps[A](val base: A) extends AnyVal {
def update(change: A)(implicit update: Lazy[Update[A]]): A =
update.value(base, change)
}
今、私たちが行うことができます。
case class Foo(a: Option[Int], b: List[Int], c: Option[Int])
val base = Foo(None, Nil, Some(0))
val update = Foo(Some(3), List(4), None)
base update update // Foo(Some(3),List(4),Some(0))
我々はcats.SemigroupK
のインスタンスを定義できますかscalaz.Plus
したがって、Option
とList
のインスタンスを省略することができましたES、例えばUpdate[Vector[Int]]
得ながら:あなたはPoly
とmap
は非常に一般的な方法でこの問題を解決するために使用することができます
import cats.SemigroupK
import cats.implicits._
implicit def semigroupKUpdate[F[_], A](implicit F: SemigroupK[F]): Update[F[A]] =
new Update[F[A]] {
def apply(base: F[A], update: F[A]): F[A] = F.combineK(update, base)
}
ニースの解決策、thx! 'genericUpdate'を別の特性に入れているのはなぜですか?なぜ更新でそれを持っていないのですか? –
それはそうですが、 'Update'でうまくいくはずです。しかし、例えば、カスタムの 'Update((A、B)]'を作成したい場合、 'genericUpdate'は' trait'の中にある必要があります。そうしないと、あいまいなimplicitsを得ることになります。 –
私はコンパイルエラーがあるので、 'Update [Foo]'暗黙的に見つけることができません。私は 'Update'特性とオブジェクトをファイルに持っています。パッケージオブジェクト内の '' UpdateOps [A] '。パッケージオブジェクトと 'Update'オブジェクトの内容の両方をインポートします。 'GenericUpdate'が見つからないようです。もう一つの注意点では、 'genericUpdate'で' G'とは何ですか? –