List,Options和其他复杂类型

时间:2015-11-04 10:53:37

标签: scala higher-kinded-types

我还在学习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)。

1 个答案:

答案 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变换器可以在OptionList[Option[A]]Future[Option[A]]等顶部堆叠任何monad。
  • ListT变换器可以在ListOption[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)))