我有一个与收集monad非常相似的monad。我正在尝试为它实现monad变换器,但我失败了。
我查看了ListT
6和7中的Scalaz
实现,但我无法理解它是如何工作的。它使用了一些额外的类型Step
,我的目的不明确。
有人可以通过解释Scalaz
方法或使用不同的实现来向我解释如何实现列表monad转换器吗?
答案 0 :(得分:18)
我不太确定,Step在scalaz中意味着什么,但实现ListT
非常简单。根据您想要添加的操作数量,它可能有点工作,但基本的monad操作可以按如下方式实现。
首先我们需要monad和functor的类型类(我们也可以添加applicative,但这不是本例所必需的):
trait Functor[F[_]] {
def map[A,B](fa: F[A])(f: A => B): F[B]
}
trait Monad[F[_]] extends Functor[F] {
def flatMap[A,B](fa: F[A])(f: A => F[B]): F[B]
def pure[A](x: A): F[A]
}
object Monad {
implicit object ListMonad extends Monad[List] {
def map[A,B](fa: List[A])(f: A => B) = fa map f
def flatMap[A,B](fa: List[A])(f: A => List[B]) = fa flatMap f
def pure[A](x: A) = x :: Nil
}
implicit object OptionMonad extends Monad[Option] {
def map[A,B](fa: Option[A])(f: A => B) = fa map f
def flatMap[A,B](fa: Option[A])(f: A => Option[B]) = fa flatMap f
def pure[A](x: A) = Some(x)
}
def apply[F[_] : Monad]: Monad[F] = implicitly[Monad[F]]
}
一旦我们有了这些,我们就可以创建变换器,它基本上只包装F[List[A]]
并通过调用{{1}将调用转发到其map
和flatMap
函数到列表在包含仿函数上,然后调用map
或map
resp。在包含的flatMap
/ s。
List
完成修改后,我们可以通过调用final case class ListT[F[_] : Monad, A](fa: F[List[A]]) {
def map[B](f: A => B) = ListT(Monad[F].map(fa)(_ map f))
def flatMap[B](f: A => ListT[F, B]) = ListT(Monad[F].flatMap(fa) { _ match {
case Nil => Monad[F].pure(List[B]())
case list => list.map(f).reduce(_ ++ _).run
}})
def ++(that: ListT[F,A]) = ListT(Monad[F].flatMap(fa) { list1 =>
Monad[F].map(that.run)(list1 ++ _)
})
def run = fa
}
对象上的run
方法来获取生成的对象。如果需要,还可以添加其他列表特定操作,例如scalaz。这应该是非常直接的。例如,ListT
可能如下所示:
::
用法:
def ::(x: A) = ListT(Monad[F].map(fa)(x :: _))
答案 1 :(得分:1)
我认为scalaz.ListT
在scalaz 7.0.x和7.1.x中不正确。
https://github.com/scalaz/scalaz/issues/921
6.x版本是正确的。但它与StreamT
相同。