如何在 scalaz 中堆叠 ReaderT 和 WriterT 变压器?
How to stack ReaderT and WriterT transformers in scalaz?
我正在 scalaz
玩 monad 转换器。我正在尝试将 Reader 顶部的 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, String, 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, W, ?], I] {
def ask: WriterT[F, W, I] = MonadTrans[WriterT[?[_], W, ?]].liftM(F.ask)
def local[A](f: I => I)(fa: WriterT[F, W, A]): WriterT[F, W, A] =
fa.mapT(F.local(f))
def point[A](a: => A): WriterT[F, W, A] = a.point[WriterT[F, W, ?]]
def bind[A, B](fa: WriterT[F, W, A])(
f: A => WriterT[F, W, B]
): WriterT[F, W, B] = fa.flatMap(f)
}
请注意,我使用的是 kind-projector,因为类型 lambda 版本的长度是 Haskell 版本的四到五倍,而不是仅仅三倍。
定义此实例后,您可以编写以下内容:
import scalaz.{ Id, MonadListen, ReaderT }
import scalaz.std.list._
type P[A] = ReaderT[Id.Id, String, 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 转换器。我正在尝试将 Reader 顶部的 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, String, 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, W, ?], I] {
def ask: WriterT[F, W, I] = MonadTrans[WriterT[?[_], W, ?]].liftM(F.ask)
def local[A](f: I => I)(fa: WriterT[F, W, A]): WriterT[F, W, A] =
fa.mapT(F.local(f))
def point[A](a: => A): WriterT[F, W, A] = a.point[WriterT[F, W, ?]]
def bind[A, B](fa: WriterT[F, W, A])(
f: A => WriterT[F, W, B]
): WriterT[F, W, B] = fa.flatMap(f)
}
请注意,我使用的是 kind-projector,因为类型 lambda 版本的长度是 Haskell 版本的四到五倍,而不是仅仅三倍。
定义此实例后,您可以编写以下内容:
import scalaz.{ Id, MonadListen, ReaderT }
import scalaz.std.list._
type P[A] = ReaderT[Id.Id, String, 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")
}
}