如何在scalaz中堆叠ReaderT和WriterT变换器?

前端之家收集整理的这篇文章主要介绍了如何在scalaz中堆叠ReaderT和WriterT变换器?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我在 scalaz玩monad变形金刚.我正在尝试将读取器顶部的Writer与底层Id monad堆叠在一起.为了组合它们,我使用的是MonadReader和MonadWriter类型.

我设法编译并运行以下代码示例而没有编写器(即使用Reader monad,即ReaderT [Id.Id,String,A]).将WriterT添加到堆栈时,我收到编译错误

Gist.scala:10: could not find implicit value for parameter F: scalaz.MonadReader[Gist.R,String]
   val MR = MonadReader[R,String]
                       ^

如何为变换器堆栈获取MonadReader实例?我是否必须使用ReaderWriterStateT或者还有其他方法吗?

完整代码

import scalaz.{Id,MonadListen,MonadReader,ReaderT,WriterT}

object Gist {
  import scalaz.std.list._
  import scalaz.Syntax.monad._

  type P[A] = ReaderT[Id.Id,A]
  type R[A] = WriterT[P,List[String],A]

  val MR = MonadReader[R,String]
  val MW = MonadListen[R,List[String]]

  def apply: R[String] = MR.ask >>= { greeting =>
    MW.tell(List(s"greeting $greeting")) >>= { _ =>
      MW.point(s"Hello $greeting")
    }
  }
}

解决方法

我不完全确定Scalaz为什么不提供这个实例(或类似的monad变换器的MonadReader实例),但我猜这个答案与WriterTInstanceN已经 goes past 11并在MonadReader中添加的事实有关更糟糕的是.

您可以在Scalaz的GitHub问题中进行挖掘(或者甚至在IRC频道询问您是否有这种事情的胃),但我不确定答案是否重要.

您可以直接从Haskell的mtl中移植实例:

instance (Monoid w,MonadReader r m) => MonadReader r (Strict.WriterT w m) where
    ask   = lift ask
    local = Strict.mapWriterT . local
    reader = lift . reader

翻译成Scala的内容如下所示:

import scalaz.{ MonadReader,MonadTrans,Monoid,WriterT }
import scalaz.Syntax.monad._

implicit def monadReaderForWriterT[F[_],I,W](implicit
  F: MonadReader[F,I],W: Monoid[W]
): MonadReader[WriterT[F,W,?],I] = new MonadReader[WriterT[F,I] {
  def ask: WriterT[F,I] = MonadTrans[WriterT[?[_],?]].liftM(F.ask)

  def local[A](f: I => I)(fa: WriterT[F,A]): WriterT[F,A] =
    fa.mapT(F.local(f))

  def point[A](a: => A): WriterT[F,A] = a.point[WriterT[F,?]]
  def bind[A,B](fa: WriterT[F,A])(
    f: A => WriterT[F,B]
  ): WriterT[F,B] = fa.flatMap(f)
}

请注意,我使用的是kind-projector,因为lambda版本的类型将更像Haskell版本的四到五倍而不是三倍.

一旦定义了此实例,就可以编写以下内容

import scalaz.{ Id,ReaderT }
import scalaz.std.list._

type P[A] = ReaderT[Id.Id,A]
type R[A] = WriterT[P,A]

val MR = MonadReader[R,String]
val MW = MonadListen[R,List[String]]

def apply: R[String] = MR.ask >>= { greeting =>
  MW.tell(List(s"greeting $greeting")) >>= { _ =>
    MW.point(s"Hello $greeting")
  }
}

猜你在找的Scala相关文章