2017-02-05 11 views
1

私はカテゴリ理論を学んでいます。私は読者のモナドの概念を理解 は、それが実装するのにも非常に簡単です:リーダーモナド - それはMonadインターフェイスにどのように準拠していますか?

case class Reader[DEP, A](g: DEP => A) { 
    def apply(dep: DEP): A = g(dep) 

    def map[B](f: A => B): Reader[DEP, B] = Reader(dep => f(apply(dep))) 

    def flatMap[B](f: A => Reader[DEP, B]): Reader[DEP, B] = Reader(dep => f(apply(dep)) apply dep) 
} 

は、しかし、私はいくつかの一般的なモナドインターフェイスへの制約とそれを実装する問題を抱えている、すなわちLETのは、のために忘れてしまった

trait Monad[A] { 
    def pure(a: A): Monad[A] 

    def map[B](f: A => B): Monad[B] 

    def flatMap[B](f: A => Monad[B]): Monad[B] 
} 

もう1つは、アプリケーションやファンクタがあり、ここに3つのメソッドを入れてみましょう。

今、このインタフェースを使用すると、ReaderMonadの実装に問題があります。 マップメソッドはかなり複雑ですが、純粋なマップマップとflatMapはどうでしょうか? Reader上で純粋なことはどういう意味ですか? flatMapを実装するには、AからReader [DEP、B]までの関数を用意する必要がありますが、A => Monad [B]があるため、適用することはできません。

case class Reader[DEP, A](g: DEP => A) extends Monad[A] { 
    def apply(dep: DEP): A = g(dep) 

    override def pure(a: A): Reader[DEP, A] = Reader(_ => a) // what does it even mean in case of Reader 

    override def map[B](f: (A) => B): Reader[DEP, B] = Reader(dep => f(apply(dep))) 

    override def flatMap[B](f: (A) => Monad[B]): Reader[DEP, B] = ??? // to implement it, I need f to be (A) => Reader[DEP, B], not (A) => Monad[B] 
} 

このようにスカラーで実装することはできますか?私はセルフバウンド型で遊んだりしようとしましたが、どちらもうまくいきませんでした。 私はscalazやcatsのようなライブラリを知っていますが、これらのタイプを実装するためにtypeclassesを使用していますが、これは教育目的にすぎません。

+0

私はネイティブの実装を見て、どのようにそれを行うかを見ていきたいと思います。あなたがハスケルを知っているなら(もしそうでなくても)、読者のMonadの定義を見てみる価値があるかもしれません。 – Carcigenicate

+0

まあまあ、彼らは完全に異なった構文(主に型抜き)を使っていますので、私は助けになるか分かりません – slnowak

+0

これの主な問題はあなたの 'Monad'特性が間違っているためです。 。通常の実装は、 'Monad'特性を型コンストラクタでパラメータ化し、' Reader [DEP、_] 'のために定義することです。 – Lee

答えて

2

flatMapを実装しようとしたときに発見したように、Monad特性を宣言する際の問題は、連鎖操作時に定義している特定のモナドタイプを失うことです。 Monad特性を定義する通常の方法は、モナドインスタンスが定義されている型コンストラクタによってパラメータをパラメータ化することです。

trait Monad[M[_]] { 
    def pure[A](a: A): M[A] 
    def map[A, B](f: A => B, m: M[A]): M[B] 
    def flatMap[A, B](f: A => M[B], m : M[A]): M[B] 
} 

だからMListまたはOptionなどの単項型コンストラクタです。 Reader[DEP, A]は、Aの値を返す、ある種の環境タイプDEPに依存する計算であると考えることができます。この2つの型パラメータを持っているので、あなたはモナドのインスタンスを定義するときに環境パラメータの種類を修正する必要があります。

case class Reader[DEP, A](g: DEP => A) 

class ReaderMonad[DEP]() extends Monad[({type t[X] = Reader[DEP, X]})#t] { 
    def pure[A](a: A) = Reader[DEP, A](_ => a) 
    def map[A, B](f: A => B,m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env))) 
    def flatMap[A, B](f: A => Reader[DEP,B],m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)).g(env)) 
} 

({type t[X] = Reader[DEP, X]})#tが部分的にReader[DEP, A]ための2つのパラメータのいずれかを適用するために使用type lambdaです。

pureは、環境を無視して指定された値を直接返すReaderを返します。

flatMapを実行すると、実行時に内部計算が実行され、結果を使用して次の計算が構築され、同じ環境で実行されます。

+0

ありがとう!そのタイプのラムダは見て...興味深い、少なくとも。 – slnowak

+2

100Kのおめでとう! –

+0

@YuvalItzchakov - ありがとう! – Lee

関連する問題