2016-04-12 37 views
2
data T b = E | N b (T b) (T b) 


f :: T b -> Reader Int (T Int) 
f (N i l r) = ask >>= \x -> local ((-)4) (f l) >>= \l' -> local ((-)1) (f r) >>= \r' -> return (N x l' r') 
f E = return E 

私はこのコードがどのように機能するかを理解することに問題があります。特に、askはどのように環境がわかるのですか(ここではちょうどInt)?Readerモナドの「質問」機能はどのように機能しますか?

より正確には:私は不可欠プログラマだと、このような言語では、それは簡単です。メソッドは、obj.f()のようなオブジェクトで呼び出すことができます。または、関数が外部データを使用するためには、引数でデータを渡す必要があります。

+0

[Reader Monad Purpose](http://stackoverflow.com/questions/14178889/reader-monad-purpose)の可能な複製 – MicroVirus

+0

これは私が今週見た2番目または3番目の質問です。 ([例](http://stackoverflow.com/questions/36474647/haskell-reader-monads-depth-for-each-node-in-binary-tree))。それはMOOCのコースの割り当てなどですか? –

答えて

2

ショート、手波状の答え。 Reader Int (T Int)の値は、基本的にはタイプInt -> (T Int)の単なるラップアップされた関数です。その関数を実行するには、まずそれを抽出する必要があります。我々はrunReaderでそれを行います。

data T b = ... deriving (Show) 

main = let tree = (N 10 (N 8 E E) E) 
      g = f tree 
      h = runReader g 
     in print $ h 20 

(典型的には、単にprint $ runReader (f tree) 20を記述し、私は以下大ざっぱ類推に対応するように分割)

askMonadReader型クラスによって定義され、ReaderTモナド変圧器によって実行されるように使用されますReaderタイプを定義する)は、基本的にhに渡された引数の値を取得します。

ある意味では、Reader Int (T Int)は、askという関数を呼び出す関数gを含むオブジェクトです。 runReader gは、呼び出されたときにその引数を単に返す関数askを定義し、次にgを呼び出す新しい関数を作成します。今度はgaskを呼び出すと、最初にhに渡された引数が戻されます。

+0

「リーダーのInt(T INT)値は、本質的に、int型のちょうどラップアップ機能である - >(T INT)」 それは私のために明らかではないが、説明してください:) – Gilgamesz

+0

私はそれをしようとして、おそらくました代わりに[この説明](http://www.mjoldfield.com/atelier/2014/08/monads-reader.html)を指すほうがよいでしょう。アイデンティティモナドに適用されたトランス(型クラスを実装する)から構築するのではなく、 'Reader'モナドを直接定義します。 – chepner

4

リーダーモナドを何のようなものです。それはあなたにask関数を与え、それは "魔法のように"薄い空気から値をポップアップさせます。実際これをを使用するには、runReaderを呼び出し、それをInt環境を提供する必要があります。 Readerタイプは、runReaderコールからaskコールのそれぞれに自動的に伝播します。