我有一個非常類似於monad集合的monad。我目前正試圖爲它實現一個monad變壓器,但我失敗了。如何在Scala中實現`List` monad變換器?
我已經看過執行Scalaz
6和7,但我不明白它是如何工作的。它使用一些額外的類型Step
,其目的不明。
那麼有人可以請我解釋一下如何實現列表單子變壓器,或者通過解釋Scalaz
方法或使用不同的實現?
我有一個非常類似於monad集合的monad。我目前正試圖爲它實現一個monad變壓器,但我失敗了。如何在Scala中實現`List` monad變換器?
我已經看過執行Scalaz
6和7,但我不明白它是如何工作的。它使用一些額外的類型Step
,其目的不明。
那麼有人可以請我解釋一下如何實現列表單子變壓器,或者通過解釋Scalaz
方法或使用不同的實現?
我不太確定,這個步驟在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
包含仿函數,然後呼叫map
或flatMap
或呼叫和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))
我覺得scalaz.ListT
是scalaz的7.0.x和7.1.x.不正確
https://github.com/scalaz/scalaz/issues/921
6.x的版本是正確的。但它與StreamT
相同。
7.x版本不使用'Step',它看起來非常簡單。 https://github.com/scalaz/scalaz/blob/v7.0.3/core/src/main/scala/scalaz/ListT.scala – huynhjl
@huynhjl對,我確定我看到了使用Step的7實現,儘管。 – ziggystar