如何在Scala中实现`List` monad变换器?

时间:2013-08-23 12:33:10

标签: scala scalaz monad-transformers

我有一个与收集monad非常相似的monad。我正在尝试为它实现monad变换器,但我失败了。

我查看了ListT 6和7中的Scalaz实现,但我无法理解它是如何工作的。它使用了一些额外的类型Step,我的目的不明确。

有人可以通过解释Scalaz方法或使用不同的实现来向我解释如何实现列表monad转换器吗?

2 个答案:

答案 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}将调用转发到其mapflatMap函数到列表在包含仿函数上,然后调用mapmap 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相同。