2016-04-12 66 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)?讀者monad的「問」功能如何工作?

更確切地說:我是一個必要的程序員,在這樣的語言中很容易。可以在任何對象上調用方法,如:obj.f(),或者當我們想要函數使用外部數據時,我們必須通過參數傳遞數據。

+0

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

+0

這是我本週見到的關於二叉樹和閱讀器單子的第二個或第三個問題([例如(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;我分裂它以對應於下面的粗略類比)

ask(由MonadReader類型類定義,如由ReaderT單子變壓器實現用於定義Reader類型)基本上檢索傳遞給h的參數的值。

從某種意義上說,Reader Int (T Int)是一個對象,其中包含一個函數g,該函數調用函數askrunReader g創建了一個新函數,該函數在被調用時定義了一個函數ask,該函數僅返回其參數,然後調用g。現在當g調用ask時,它返回最初傳遞給h的參數。

+0

「Reader Int(T Int)的值本質上只是Int - >(T Int)類型的封裝函數」 對我來說這不是顯而易見的,請解釋:) – Gilgamesz

+0

我打算嘗試它,但也許取而代之的是指出你[這個解釋](http://www.mjoldfield.com/atelier/2014/08/monads-reader.html)會更好。它直接定義一個'Reader' monad,而不是從應用於身份monad的轉換器(實現一個類型類)構建它。 – chepner

4

這就是讀者單元所做的那種;它會給你一個ask的功能,「神奇地」彈出一個空氣清新的價值。要真正使用這個,你需要撥打runReader,並給它Int環境。然後Reader類型自動將呼叫從runReader呼叫傳播到每個ask呼叫。