Scala 使用 shapeless 通过自然转换组合更高种类的副产品
Scala using shapeless to combine higher kinded coproducts over a natural transformation
给定一组具有两个不同子集的 Adts
例如:
sealed trait Domain[Y]
sealed trait Command[Y] extends Domain[Y]
sealed trait Query[Y] extends Domain[Y]
case class Add(value:String) extends Command[Ack]
case class Remove(value:String) extends Command[Ack]
case class Exists(value:String) extends Query[Boolean]
case object List extends Query[List[String]]
现在假设我有两个自然变换,对于一些任意的 Monad M[_]:
val commandHandler:Command ~> M
val queryExecutor:Query ~> M
我希望以某种方式将这两个自然转换合并为一个转换:
val service:Domain ~> M = union(commandHandler, queryExecutor)
然而,我们正在努力从具有更高种类副产品的起点开始。在这个阶段,即使方向正确也会有所帮助。
好吧,这是一个非常古老的问题,但是如今,例如 cats 在 NaturalTransformation:
上提供 Coproduct
和方法 or
trait NaturalTransformation[F[_], G[_]] extends Serializable { self =>
def or[H[_]](h: H ~> G): Coproduct[F, H, ?] ~> G = ???
}
所以你可以用它来做(使用 kind-projector 作为 lambda 类型 ?
)
val combine: Coproduct[Command,Query,?] ~> M = commandHandler.or(queryExecutor)
编辑:这是一个完整的示例,它还定义了 union
(使用 Id
而不是 M
进行类型检查):
import cats._
import cats.data._
trait Ack
sealed trait Domain[Y]
sealed trait Command[Y] extends Domain[Y]
sealed trait Query[Y] extends Domain[Y]
case class Add(value:String) extends Command[Ack]
case class Remove(value:String) extends Command[Ack]
case class Exists(value:String) extends Query[Boolean]
case object List extends Query[List[String]]
def commandHandler:Command ~> Id = ???
def queryExecutor:Query ~> Id = ???
def union: Domain ~> Coproduct[Command,Query,?] = new (Domain ~> Coproduct[Command,Query,?]) {
def apply[A](fa: Domain[A]): Coproduct[Command,Query,A] = fa match {
case command: Command[A] => Coproduct.left(command)
case query: Query[A] => Coproduct.right(query)
}
}
def result: Domain ~> Id = commandHandler.or(queryExecutor).compose(union)
或者如果你想避免中间 Coproduct
:
def unionDirect[M[_]](cmd: Command ~> M, qry: Query ~> M): Domain ~> M =
new (Domain ~> M) {
def apply[A](fa: Domain[A]): M[A] = fa match {
case command: Command[A] => cmd(command)
case query: Query[A] => qry(query)
}
}
def resultDirect: Domain ~> Id = unionDirect(commandHandler,queryExecutor)
给定一组具有两个不同子集的 Adts 例如:
sealed trait Domain[Y]
sealed trait Command[Y] extends Domain[Y]
sealed trait Query[Y] extends Domain[Y]
case class Add(value:String) extends Command[Ack]
case class Remove(value:String) extends Command[Ack]
case class Exists(value:String) extends Query[Boolean]
case object List extends Query[List[String]]
现在假设我有两个自然变换,对于一些任意的 Monad M[_]:
val commandHandler:Command ~> M
val queryExecutor:Query ~> M
我希望以某种方式将这两个自然转换合并为一个转换:
val service:Domain ~> M = union(commandHandler, queryExecutor)
然而,我们正在努力从具有更高种类副产品的起点开始。在这个阶段,即使方向正确也会有所帮助。
好吧,这是一个非常古老的问题,但是如今,例如 cats 在 NaturalTransformation:
上提供Coproduct
和方法 or
trait NaturalTransformation[F[_], G[_]] extends Serializable { self =>
def or[H[_]](h: H ~> G): Coproduct[F, H, ?] ~> G = ???
}
所以你可以用它来做(使用 kind-projector 作为 lambda 类型 ?
)
val combine: Coproduct[Command,Query,?] ~> M = commandHandler.or(queryExecutor)
编辑:这是一个完整的示例,它还定义了 union
(使用 Id
而不是 M
进行类型检查):
import cats._
import cats.data._
trait Ack
sealed trait Domain[Y]
sealed trait Command[Y] extends Domain[Y]
sealed trait Query[Y] extends Domain[Y]
case class Add(value:String) extends Command[Ack]
case class Remove(value:String) extends Command[Ack]
case class Exists(value:String) extends Query[Boolean]
case object List extends Query[List[String]]
def commandHandler:Command ~> Id = ???
def queryExecutor:Query ~> Id = ???
def union: Domain ~> Coproduct[Command,Query,?] = new (Domain ~> Coproduct[Command,Query,?]) {
def apply[A](fa: Domain[A]): Coproduct[Command,Query,A] = fa match {
case command: Command[A] => Coproduct.left(command)
case query: Query[A] => Coproduct.right(query)
}
}
def result: Domain ~> Id = commandHandler.or(queryExecutor).compose(union)
或者如果你想避免中间 Coproduct
:
def unionDirect[M[_]](cmd: Command ~> M, qry: Query ~> M): Domain ~> M =
new (Domain ~> M) {
def apply[A](fa: Domain[A]): M[A] = fa match {
case command: Command[A] => cmd(command)
case query: Query[A] => qry(query)
}
}
def resultDirect: Domain ~> Id = unionDirect(commandHandler,queryExecutor)