我有一个与集合单子非常相似的单子。我目前正在尝试为它实现一个 monad 转换器,但我失败了。
我已经查看了 6 和 7 中的ListT
实现Scalaz
,但我无法理解它是如何工作的。它使用了一些额外的 type Step
,我不清楚其目的。
那么有人可以通过解释Scalaz
方法或使用不同的实现来向我解释如何实现列表单子变换器吗?
我有一个与集合单子非常相似的单子。我目前正在尝试为它实现一个 monad 转换器,但我失败了。
我已经查看了 6 和 7 中的ListT
实现Scalaz
,但我无法理解它是如何工作的。它使用了一些额外的 type Step
,我不清楚其目的。
那么有人可以通过解释Scalaz
方法或使用不同的实现来向我解释如何实现列表单子变换器吗?
我不太确定 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]]
将调用转发到它的map
和flatMap
函数到列表中。在包含的/s 上。map
map
flatMap
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
上的方法来获取结果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))
我认为scalaz.ListT
在 scalaz 7.0.x 和 7.1.x 中是不正确的。
https://github.com/scalaz/scalaz/issues/921
6.x 版本是正确的。但它与StreamT
.