简体   繁体   English

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

[英]How to implement the `List` monad transformer in Scala?

I have a monad that is very similar to a collection monad. 我有一个与集合monad非常相似的monad。 I'm currently trying to implement a monad transformer for it, but I'm failing. 我目前正在尝试为其实现monad转换器,但是失败了。

I've looked at the ListT implementation in Scalaz 6 and 7, but I cannot understand how it works. 我已经看过Scalaz 6和7中的ListT实现,但是我不明白它是如何工作的。 It uses some additional type Step , whose purpose is unclear to me. 它使用一些其他类型的Step ,其目的对我来说还不清楚。

So can someone please explain to me how to implement a list monad transformer, either by explaining the Scalaz approach or using a different implementation? 因此,有人可以通过解释Scalaz方法或使用其他实现方式向我解释如何实现列表monad转换器吗?

I am not quite sure, what the Step means in scalaz, but implementing a ListT is pretty straight forward. 我不太确定,Step在scalaz中意味着什么,但是实现ListT是非常简单的。 Depending on how many operations you want to put on it, it can be a little work, but the basic monad operations can be implemented as follows. 根据您要执行的操作数,这可能会有些麻烦,但是基本的monad操作可以实现如下。

First we need typeclasses for monad and functor (we could also add applicative, but that is not necessary for this example): 首先,我们需要monad和functor的类型类(我们也可以添加应用程序类,但这对于本示例不是必需的):

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]]

}

Once we have those, we can create the transformer, which basically just wraps the F[List[A]] and forwards the call to its map and flatMap function to the list by calling map on the containing functor and then calling map or flatMap resp. 一旦我们有了这些,我们可以创建变压器,基本上只是包装的F[List[A]]和调用转发给它的mapflatMap通过调用函数列表map上含仿函数,然后调用mapflatMap RESP 。 on the contained List /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
}

Once we are done with modifying, we can get the resulting object by calling the run method on the ListT object. 修改完成后,可以通过在ListT对象上调用run方法来获得ListT对象。 If you want, you can also add other list specific operations like in scalaz. 如果需要,还可以添加其他列表特定的操作,例如在scalaz中。 This should be pretty straight forward. 这应该很简单。 For example a :: could look as follows: 例如, ::可能如下所示:

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

Usage: 用法:

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))

I think scalaz.ListT is incorrect in scalaz 7.0.x and 7.1.x. 我认为scalaz.ListT在scalaz 7.0.x和7.1.x中不正确。

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

6.x version is correct. 6.x版本正确。 but it is same as StreamT . 但它与StreamT相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM