2011-11-23 42 views
22

我很困惑。我可以這樣寫:摺疊,功能組成,monads和懶惰,哦,我的?

import Control.Monad 

main = print $ head $ (foldr (.) id [f, g]) [3] 
    where f = (1:) 
     g = undefined 

和輸出是1。這是有道理的,因爲它簡化爲:

main = print $ head $ ((1:) . undefined . id) [3] 
main = print $ head $ (1:) ((undefined . id) [3]) 
main = print $ head $ 1 : ((undefined . id) [3]) 
main = print $ 1 

但是,如果我用一個模糊的類似單子的技術,這是行不通的一樣:

import Control.Monad 

main = print $ (foldr (<=<) return [f, g]) 3 
    where f = const Nothing 
     g = undefined 

這擊中prelude.Undefined。這是奇怪的,因爲我希望它減少:

main = print $ ((const Nothing) <=< undefined <=< return) 3 
main = print $ return 3 >>= undefined >>= (\_ -> Nothing) 
main = print $ Nothing -- nope! instead, undefined makes this blow up 

然而,翻轉的組成順序:

import Control.Monad 

main = print $ (foldr (>=>) return [f, g]) 3 
    where f = const Nothing 
     g = undefined 

沒有完成預期短路併產生Nothing

main = print $ (const Nothing >=> undefined >=> return) 3 
main = print $ (const Nothing 3) >>= undefined >>= return 
main = print $ Nothing >>= undefined >>= return 
main = print $ Nothing 

我想比較這兩種方法可能是比較蘋果和橙子,但你能解釋一下這個區別嗎?我認爲f <=< g是的一元類似物,但它們顯然不像我想象的那麼相似。你能解釋爲什麼嗎?

回答

20

這取決於您正在使用哪個單子,以及如何定義它的運算符(>>=)

在Daniel Fischer解釋的情況下,在Maybe,(>>=)的第一個參數中是嚴格的。

下面是一些其他monad的一些結果。

> :set -XNoMonomorphismRestriction 
> let foo = (const (return 42) <=< undefined <=< return) 3 
> :t foo 
foo :: (Num t, Monad m) => m t 

身份:懶惰。

> Control.Monad.Identity.runIdentity foo 
42 

IO:嚴格。

> foo :: IO Integer 
*** Exception: Prelude.undefined 

讀者:懶惰。

> Control.Monad.Reader.runReader foo "bar" 
42 

編劇:既有懶惰和嚴格的變種。

> Control.Monad.Writer.runWriter foo 
(42,()) 
> Control.Monad.Writer.Strict.runWriter foo 
*** Exception: Prelude.undefined 

國家:也同時具有嚴格的和懶惰的版本。

> Control.Monad.State.runState foo "bar" 
(42,"*** Exception: Prelude.undefined 
> Control.Monad.State.Strict.runState foo "bar" 
*** Exception: Prelude.undefined 

續:嚴格。

> Control.Monad.Cont.runCont foo id 
*** Exception: Prelude.undefined 
19

Maybe的綁定在第一個參數中是嚴格的。

Just v >>= f = f v 
Nothing >>= f = Nothing 

所以,當你嘗試

Just v >>= undefined >>= \_ -> Nothing 

你打

undefined v >>= \_ -> Nothing 

及實施需要找出undefined vNothingJust something看到使用這些(>>=)方程。

在另一方面,

Nothing >>= undefined 

確定不看的(>>=)的第二個參數的結果。