How to implement the "List" monad transformer in Scala?

I have a monad, which is very similar to the collection monad. I am currently trying to implement a monad transformer for this, but I fail.

I reviewed the implementation of ListT in Scalaz 6 and 7, but I cannot figure out how this works. He uses some additional type of Step , the purpose of which is incomprehensible to me.

So can someone please explain to me how to implement a list monad transformer, explaining Scalaz approach or using another implementation?

+7
scala scalaz monad-transformers
source share
2 answers

I'm not quite sure what Step means in scalaz, but the ListT implementation ListT pretty straight forward. Depending on how many operations you want to put on it, this may be a bit of work, but the basic operations of a monad can be implemented as follows.

First we need classes for monad and functor (we could also add applicative ones, but this is not necessary for this example):

 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 get them, we can create a transformer that basically just wraps F[List[A]] and redirects its map and flatMap to a list, calling map on the containing functor, and then calling map or flatMap respectively. on containing List / s.

 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 } 

As soon as we finish with the modification, we will get the received object by calling the run method of the ListT object. If you want, you can also add other list operations, for example, in scalaz. This should be pretty straight forward. For example, :: might look like this:

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

Using:

 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)) 
+17
source share

I think scalaz.ListT is wrong in scalaz 7.0.x and 7.1.x.

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

version 6.x is correct. but he is the same as StreamT .

+1
source share

All Articles