我还在学习Scala - 所以请原谅我,如果这非常简单。我对Scalaz或Shapeless也不是很流利 - 我只是开始探索这些库。我正在寻找一个简单的论文,向我解释我如何能做到这样的事情
trait AmazingMalini[F[G[_]]] {
def fMap[A,B](aa: F[G[A]])(f : A => F[G[B]]) : F[G[B]]
}
然后我想做这样的事情 -
trait SomeCrazyMagicWithList extends AmazingMalini[Option[List]]{
def fMap[A,B](aa: Option[List[A]])(f : A => Option[List[B]]) :Option[List[B]] = ???
}
请注意,选项或列表类型只是示例我有一些容器类型,我会在那里替换它们(为应用程序构建一个小的图形遍历,如DSL)。
答案 0 :(得分:5)
您必须将AmazingMalini
的签名更改为trait AmazingMalini[F[_], G[_]]
然后可以像这样实现该方法:
trait AmazingMalini[F[_], G[_]] {
def fMap[A,B](aa: F[G[A]])(f : A => F[G[B]]) : F[G[B]]
}
trait SomeCrazyMagicWithList extends AmazingMalini[Option, List] {
def fMap[A, B](aa: Option[List[A]])(f: A => Option[List[B]]): Option[List[B]] =
aa.flatMap {
_ match {
case Nil => Some(Nil)
case as: List[A] => as.map(f).reduce(concat(_, _))
}
}
def concat[A](x: Option[List[A]], y: Option[List[A]]): Option[List[A]] = for {
xs <- x
ys <- y
} yield xs ++ ys
}
请注意,Scalaz提供monad transformers以启用某些monad的堆叠。例如:
OptionT
变换器可以在Option
:List[Option[A]]
,Future[Option[A]]
等顶部堆叠任何monad。ListT
变换器可以在List
:Option[List[A]]
,Future[List[A]]
之上堆叠任何monad。因此,在您的情况下,您可以像这样使用ListT
:
import scalaz._
import Scalaz._
import ListT._
listT(List(1,2,3).some).flatMap(i => listT(List(i, i * 3).some))
res0: scalaz.ListT[Option,Int] = ListT(Some(List(1, 3, 2, 6, 3, 9)))
你也可以使用monad变换器的for-comprehensions:
for {
x <- listT(List(1,2).some)
y <- listT(List(3,4).some)
} yield x + y
res2: scalaz.ListT[Option,Int] = ListT(Some(List(4, 5, 5, 6)))