我有
F ~> H
G ~> H
~>
在哪里cats.NaturalTransformation
。
我能够构建一个
λ[A => F[A] :+: G[A] :+: CNil] ~> H
使用kind-projector语法以提高可读性
这就是我的做法
def or[G[_]](g: G ~> H): λ[A => F[A] :+: G[A] :+: CNil] ~> H =
new (λ[A => F[A] :+: G[A] :+: CNil] ~> H) {
def apply[A](fa: F[A] :+: G[A] :+: CNil): H[A] =
(fa.select[F[A]], fa.select[G[A]]) match {
case (Some(ff), None) => f(ff)
case (None, Some(gg)) => g(gg)
// this can't happen, due to the definition of Coproduct
case _ => throw new Exception("Something is wrong")
}
}
这可行,尽管我愿意接受建议,因为它看起来并不漂亮。
现在,如果我有
λ[A => F[A] :+: G[A] :+: CNil] ~> H
K ~> H
我也应该能够构建一个
λ[A => F[A] :+: G[A] :+: K[A] :+: CNil] ~> H
这就是我卡住的地方。我尝试ExtendRight
从 shapeless 使用,但我无法让它工作。这是我的尝试:
def or[F[_] <: Coproduct, G[_], H[_], FG[_] <: Coproduct](f: F ~> H, g: G ~> H)(
implicit e: ExtendRight.Aux[F[_], G[_], FG[_]]
): FG ~> H = new (FG ~> H) {
def apply[A](fg: FG[A])(implicit
sf: Selector[FG[A], F[A]],
sg: Selector[FG[A], G[A]]
): H[A] =
(fg.select[F[A]], fg.select[G[A]]) match {
case (Some(ff), None) => f(ff)
case (None, Some(gg)) => g(gg)
// this can't happen, due to the definition of Coproduct
case _ => throw new Exception("Something is wrong")
}
}
但是编译器找不到ExtendRight
参数的隐含证据。
这是一个可以玩的 MWE
import shapeless._
import shapeless.ops.coproduct._
import cats.~>
object Bar {
val optionToList = new (Option ~> List) {
def apply[A](x: Option[A]): List[A] = x match {
case None => Nil
case Some(a) => List(a)
}
}
val idToList = new (Id ~> List) {
def apply[A](x: Id[A]): List[A] = List(x)
}
val tryToList = new (scala.util.Try ~> List) {
def apply[A](x: scala.util.Try[A]): List[A] = x match {
case scala.util.Failure(_) => Nil
case scala.util.Success(a) => List(a)
}
}
type OI[A] = Option[A] :+: Id[A] :+: CNil
val optionAndId: OI ~> List = Foo.or(optionToList, idToList)
val all = Foo.or2(optionAndId, tryToList)
}
object Foo {
def or[F[_], G[_], H[_]](f: F ~> H, g: G ~> H): λ[A => F[A] :+: G[A] :+: CNil] ~> H =
new (λ[A => F[A] :+: G[A] :+: CNil] ~> H) {
def apply[A](fa: F[A] :+: G[A] :+: CNil): H[A] =
(fa.select[F[A]], fa.select[G[A]]) match {
case (Some(ff), None) => f(ff)
case (None, Some(gg)) => g(gg)
// this can't happen, due to the definition of Coproduct
case _ => throw new Exception("Something is wrong, most likely in the type system")
}
}
def or2[F[_] <: Coproduct, G[_], H[_], FG[_] <: Coproduct](f: F ~> H, g: G ~> H)(implicit
e: ExtendRight.Aux[F[_], G[_], FG[_]]
): FG ~> H = new (FG ~> H) {
def apply[A](fg: FG[A])(implicit
sf: Selector[FG[A], F[A]],
sg: Selector[FG[A], G[A]]
): H[A] =
(fg.select[F[A]], fg.select[G[A]]) match {
case (Some(ff), None) => f(ff)
case (None, Some(gg)) => g(gg)
// this can't happen, due to the definition of Coproduct
case _ => throw new Exception("Something is wrong, most likely in the type system")
}
}
}