![](/img/trans.png)
[英]How does the ask function know the enrivonment to return in the Reader monad?
[英]How does the Reader monad's "ask" function work?
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
)?
更准確地說:我是一個命令式程序員,使用這種語言很容易。 可以在任何 object 上調用方法,例如: obj.f()
,或者當我們希望 function 使用外部數據時,我們必須通過參數傳遞數據。
這就是Reader monad的功能 ; 它為您提供了一個ask
功能,“神奇地”突然彈出一個值。 要實際使用它,您需要調用runReader
,並為其提供Int
環境。 然后, Reader
類型將其自動從runReader
調用傳播到每個ask
調用。
簡短的手工波浪形答案。 Reader Int (T Int)
值本質上只是Int -> (T Int)
類型的包裝函數。 為了運行該功能,我們首先需要提取它。 我們使用runReader
做到這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
類型類定義,並由用於定義Reader
類型的ReaderT
monad轉換Reader
)基本上檢索傳遞給h
的參數的值。
從某種意義上說, Reader Int (T Int)
是一個包含函數g
的對象,該函數調用函數ask
。 runReader g
創建一個新函數,該函數在被調用時定義一個簡單地返回其參數的ask
函數,然后調用g
。 現在,當g
調用ask
,它將返回最初傳遞給h
的參數。
我建議先閱讀這篇文章。 問定義:
ask :: (Monad m) => ReaderT r m r
ask = ReaderT return
和讀者:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
type Reader r = ReaderT r Identity
所以
do
r <- ask
...
相當於
do
r <- ReaderT return
...
所以本質上<-
只是進入 identity monad,並獲取最終將被runReader R = return
提升的任何價值。
這將啟用 haskell 中的全局變量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.