2013-08-23 27 views
7

我有一個非常類似於monad集合的monad。我目前正試圖爲它實現一個monad變壓器,但我失敗了。如何在Scala中實現`List` monad變換器?

我已經看過執行Scalaz 6和7,但我不明白它是如何工作的。它使用一些額外的類型Step,其目的不明。

那麼有人可以請我解釋一下如何實現列表單子變壓器,或者通過解釋Scalaz方法或使用不同的實現?

+1

7.x版本不使用'Step',它看起來非常簡單。 https://github.com/scalaz/scalaz/blob/v7.0.3/core/src/main/scala/scalaz/ListT.scala – huynhjl

+0

@huynhjl對,我確定我看到了使用Step的7實現,儘管。 – ziggystar

回答

17

我不太確定,這個步驟在scalaz中意味着什麼,但是實施ListT是非常簡單的。取決於你想要投入多少操作,這可能是一個小工作,但基本monad操作可以按如下方式實現。

首先,我們需要對單子和函子類型類(我們還可以添加應用性,但是這是沒有必要在這個例子中):

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]]並通過調用map包含仿函數,然後呼叫mapflatMap或呼叫和flatMap函數將呼叫轉發到列表。包含在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 
} 

一旦我們修改完成後,我們可以通過調用ListT對象上run方法獲取生成的對象。如果你願意,你也可以像在斯卡拉一樣添加其他列表特定的操作。這應該是非常簡單的。例如,一個::可以看看如下:

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)) 
相關問題