1am*_*bda 7 scala scalaz shapeless
正如我所知,无形提供了HList(异类列表)类型,它可以包含多种类型.
可折叠HList吗?例如,
// ref - Composable application architecture with reasonably priced monad
// code - https://github.com/stew/reasonably-priced/blob/master/src/main/scala/reasonable/App.scala
import scalaz.{Coproduct, Free, Id, NaturalTransformation}
def or[F[_], G[_], H[_]](f: F ~> H, g: G ~> H): ({type cp[?] = Coproduct[F,G,?]})#cp ~> H =
new NaturalTransformation[({type cp[?] = Coproduct[F,G,?]})#cp,H] {
def apply[A](fa: Coproduct[F,G,A]): H[A] = fa.run match {
case -\/(ff) ? f(ff)
case \/-(gg) ? g(gg)
}
}
type Language0[A] = Coproduct[InteractOp, AuthOp, A]
type Language[A] = Coproduct[LogOp, Language0, A]
val interpreter0: Language0 ~> Id = or(InteractInterpreter, AuthInterpreter)
val interpreter: Language ~> Id = or(LogInterpreter, interpreter0)
// What if we have `combine` function which folds HList
val interpreters: Language ~> Id = combine(InteractInterpreter :: AuthInterpreter :: LoginInterpreter :: HNil)
Run Code Online (Sandbox Code Playgroud)
甚至,我可以简化生成Langauge吗?
type Language0[A] = Coproduct[InteractOp, AuthOp, A]
type Language[A] = Coproduct[LogOp, Language0, A]
// What if we can create `Language` in one line
type Language[A] = GenCoproduct[InteractOp, AuthOp, LogOp, A]
Run Code Online (Sandbox Code Playgroud)
为了完整的工作示例,假设我们有一些简单的代数:
sealed trait AuthOp[A]
case class Login(user: String, pass: String) extends AuthOp[Option[String]]
case class HasPermission(user: String, access: String) extends AuthOp[Boolean]
sealed trait InteractOp[A]
case class Ask(prompt: String) extends InteractOp[String]
case class Tell(msg: String) extends InteractOp[Unit]
sealed trait LogOp[A]
case class Record(msg: String) extends LogOp[Unit]
Run Code Online (Sandbox Code Playgroud)
还有一些(毫无意义但可编译)的口译员:
import scalaz.~>, scalaz.Id.Id
val AuthInterpreter: AuthOp ~> Id = new (AuthOp ~> Id) {
def apply[A](op: AuthOp[A]): A = op match {
case Login("foo", "bar") => Some("foo")
case Login(_, _) => None
case HasPermission("foo", "any") => true
case HasPermission(_, _) => false
}
}
val InteractInterpreter: InteractOp ~> Id = new (InteractOp ~> Id) {
def apply[A](op: InteractOp[A]): A = op match {
case Ask(p) => p
case Tell(_) => ()
}
}
val LogInterpreter: LogOp ~> Id = new (LogOp ~> Id) {
def apply[A](op: LogOp[A]): A = op match {
case Record(_) => ()
}
}
Run Code Online (Sandbox Code Playgroud)
此时你应该可以折叠这样HList的解释器:
import scalaz.Coproduct
import shapeless.Poly2
object combine extends Poly2 {
implicit def or[F[_], G[_], H[_]]: Case.Aux[
F ~> H,
G ~> H,
({ type L[x] = Coproduct[F, G, x] })#L ~> H
] = at((f, g) =>
new (({ type L[x] = Coproduct[F, G, x] })#L ~> H) {
def apply[A](fa: Coproduct[F, G, A]): H[A] = fa.run.fold(f, g)
}
)
}
Run Code Online (Sandbox Code Playgroud)
但是,这似乎与类型推断有关的原因不起作用.但是,编写自定义类型类并不困难:
import scalaz.Coproduct
import shapeless.{ DepFn1, HList, HNil, :: }
trait Interpreters[L <: HList] extends DepFn1[L]
object Interpreters {
type Aux[L <: HList, Out0] = Interpreters[L] { type Out = Out0 }
implicit def interpreters0[F[_], H[_]]: Aux[(F ~> H) :: HNil, F ~> H] =
new Interpreters[(F ~> H) :: HNil] {
type Out = F ~> H
def apply(in: (F ~> H) :: HNil): F ~> H = in.head
}
implicit def interpreters1[F[_], G[_], H[_], T <: HList](implicit
ti: Aux[T, G ~> H]
): Aux[(F ~> H) :: T, ({ type L[x] = Coproduct[F, G, x] })#L ~> H] =
new Interpreters[(F ~> H) :: T] {
type Out = ({ type L[x] = Coproduct[F, G, x] })#L ~> H
def apply(
in: (F ~> H) :: T
): ({ type L[x] = Coproduct[F, G, x] })#L ~> H =
new (({ type L[x] = Coproduct[F, G, x] })#L ~> H) {
def apply[A](fa: Coproduct[F, G, A]): H[A] =
fa.run.fold(in.head, ti(in.tail))
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以写下你的combine:
def combine[L <: HList](l: L)(implicit is: Interpreters[L]): is.Out = is(l)
Run Code Online (Sandbox Code Playgroud)
并使用它:
type Language0[A] = Coproduct[InteractOp, AuthOp, A]
type Language[A] = Coproduct[LogOp, Language0, A]
val interpreter: Language ~> Id =
combine(LogInterpreter :: InteractInterpreter :: AuthInterpreter :: HNil)
Run Code Online (Sandbox Code Playgroud)
您可能能够使该Poly2版本正常工作,但这种类型类对我来说可能很简单.不幸的是,你无法以Language你想要的方式简化类型别名的定义.
| 归档时间: |
|
| 查看次数: |
653 次 |
| 最近记录: |