2017-04-11 18 views
4

私はモナド変圧器でscalazで遊んでいます。私は基盤のIdモナドと一緒にリーダーの上にライターを積み重ねようとしています。それらを組み合わせるために、私はMonadReaderMonadWriterタイプのクラスを使用しています。ReaderTとWriterTトランスをscalazに積み重ねる方法は?

私は(ReaderT[Id.Id, String, A]すなわち、すなわちReaderモナドで)せずに次のコードサンプルをコンパイルして実行するためにライターを管理していました。スタックに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") 
    } 
    } 
} 

答えて

5

私はScalazこのインスタンス(または類似のモナド変圧器のためのMonadReaderインスタンス)を提供していない理由は全くわからないんだけど、私は答えを推測すると思いますがとは何かを持っています事実、WriterTInstanceNはすでにgoes past 11であり、MonadReaderで追加するだけで、もっと混乱することになります。

あなたはScalazのGitHubの問題を掘り下げることができます(または、あなたがそのような種類の胃を持っている場合はIRCチャネルに問い合わせてください)。しかし、私は答えがそれほど重要であるかどうかはわかりません。

あなたはかなり素直Haskellのmtlからポートインスタンスをすることができます:私は型ラムダバージョン以来、kind-projectorを使用してい

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) 
} 

注:

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

スカラ座に翻訳され、このようになります。わずか3倍ではなく、ハスケルバージョンの4倍から5倍に似ています。

あなたはこのインスタンスを定義したら、次のよう記述することができます。魔法のように

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") 
    } 
} 
+0

作品。教授の目的のために、 'scalaz'実装を持たない別のトランススタック/型クラスの組み合わせについて考えることができますか?それで自分の実装を書くことを練習できますか? – mgryszko

+0

@mgryszko Haskellのmtl [here](https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Reader-Class.html)-StateT'のリストを見ることができます。 'ListT'、' ContT'、 'EitherT'、' IdT'などはすべて良い候補です。 –

関連する問題