[英]Continuation Monad - Int and String
《 Monads of the Monads》文章介紹了以下代碼:
ex3 = do
a <- return 1
b <- ContT (\fred -> "escape")
return $ a+b
然后我可以執行它:
ghci> runContT ex3 show
"escape"
但是我不能跑步:
ghci> runContT ex3 id
<interactive>:51:14:
Couldn't match type ‘[Char]’ with ‘Integer’
Expected type: Integer -> [Char]
Actual type: Integer -> Integer
In the second argument of ‘runContT’, namely ‘id’
In the expression: runContT ex3 id
如何return $ a+b
類型檢查?
runCont ex3 show
什么? runCont ex3 id
怎么樣-好像不能接受Int + [Char]
-但是為什么要編譯?
首先,讓我們看看Cont
是如何定義的:
data Cont r a = Cont {runCont :: (a -> r) -> r}
如果放大此聲明,將會看到Cont
包裝了一個函數,給定一個函數(a->r)
會生成r
。 換句話說,它“隱藏” runCont
內部類型為a
(或r
)的runCont
。 因此, do
表達式中存在Cont (\\fred -> "escape")
( fred
是一個函數,將被忽略)告訴我們r
是String
,並且整個表達式的runCont
被固定為返回String
類型的值,並且對於某些a
只能接受a->String
類型的函數,我們需要對其進行求解。
現在讓我們看看return
是什么樣的:
instance Monad (Cont r) where
return x = Cont ($ x) -- given a function, pass x to it
(Cont m) >>= f = -- f :: a -> Cont r b, which roughly means
-- f :: a -> (b->r) -> r
-- which would roughly be Cont (\g -> m (flip f g))
-- notice we pass f to m: f is the stuff that needs
-- executing when m needs to; f is continuation of m
let h g x = let (Cont n) = f x -- unwrap (b->r)->r
in n g
in Cont (m . h)
-- or Cont (\g -> m (($ g) . runCont . f)), if that's easier to read
注意>>=
工作方式。 如果m
不使用傳遞給它的函數-請記住, runCont
可能會直接“隱藏”類型r
的值,不一定是“ a
”類型的值-然后是“ continuation”( fred
in Cont (\\fred -> "escape")
)沒有被調用,您將觀察到“轉義”。
因此, a <- return 1
表示a :: Integer
,顯然, b <- Cont (\\_ -> "escape")
並不表示b :: String
相反, b
可以是任何類型-函數fred
傳遞給Cont
被忽略,因此任何返回String
函數都可以使用-但是b
的類型由表達式的其余部分固定。 return $ a + b
只是表示Cont String Integer
因為a
是Integer
,所以b
也固定為Integer
。
此外,觀察到由定義show
在runCont ex3 show
注定作為最后一行的延續do
表情:是指對線路return $ a+b
,所以你的意思傳遞類型的函數Integer -> r
因為a+b
是Integer
,並且您打算傳遞a- a -> String
類型的函數,因為r
由表達式b <- Cont (\\_ -> "escape")
。
這樣,整個表達式等效於以下內容:
do
a <- return 1
b <- Cont (\_ -> "escape")
return $ (a+b)
==
return 1 >>= (\a -> (Cont (\_ -> "escape") >>= (\b -> return (a+b))))
== -- apply return rule
Cont ($ 1) >>= (\a -> (Cont (\_ -> "escape") >>=
(\b -> Cont ($ (a+b)))))
== -- apply >>= rule
Cont (\g -> ($ 1) (($ g) . runCont . (\a -> (Cont (\_ -> "escape") >>=
(\b -> Cont ($ (a+b)))))))
== -- apply >>= rule
Cont (\g -> ($ 1) (($ g) . runCont . (\a -> (Cont (\h ->
(\_ -> "escape") (($ h) . runCont . (\b -> Cont ($ (a+b)))))))))
== -- (\_ -> x) y == x
Cont (\g -> ($ 1) (($ g) . runCont . (\a -> (Cont (\h -> "escape")))))
== -- marking unused variables with "_" for clarity
Cont (\g -> ($ 1) (($ g) . runCont . (\_ -> (Cont (\_ -> "escape")))))
== -- ($ y) (\_ -> x) == x
Cont (\g -> ($ g) $ runCont (Cont (\_ -> "escape")))
== -- runCont (Cont x) == x
Cont (\g -> ($ g) (\_ -> "escape"))
== -- ($ y) (\_ -> x) == x
Cont (\_ -> "escape")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.