9

我有一个与集合单子非常相似的单子。我目前正在尝试为它实现一个 monad 转换器,但我失败了。

我已经查看了 6 和 7 中的ListT实现Scalaz,但我无法理解它是如何工作的。它使用了一些额外的 type Step,我不清楚其目的。

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

4

2 回答 2

19

我不太确定 Step 在 scalaz 中的含义,但实现 aListT非常简单。根据您要对其进行多少操作,可能会有点工作,但基本的 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]]

}

一旦我们有了这些,我们就可以创建转换器,它基本上只是包装并通过调用包含函子然后调用or来F[List[A]]将调用转发到它的mapflatMap函数到列表中。在包含的/s 上。mapmapflatMapList

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上的方法来获取结果ListT对象。如果需要,您还可以添加其他特定于列表的操作,例如在 scalaz 中。这应该很简单。例如 a::可能如下所示:

def ::(x: A) = ListT(Monad[F].map(fa)(x :: _))

用法:

scala> ListT(Option(List(1,2,3)))
res6: ListT[Option,Int] = ListT(Some(List(1, 2, 3)))

scala> res6.map(_+45)
res7: ListT[Option,Int] = ListT(Some(List(46, 47, 48)))

scala> 13 :: res7
res8: ListT[Option,Int] = ListT(Some(List(13, 46, 47, 48)))

scala> res8.run
res10: Option[List[Int]] = Some(List(13, 46, 47, 48))
于 2013-08-23T13:14:21.747 回答
1

我认为scalaz.ListT在 scalaz 7.0.x 和 7.1.x 中是不正确的。

https://github.com/scalaz/scalaz/issues/921

6.x 版本是正确的。但它与StreamT.

于 2015-06-03T17:28:03.080 回答