2012-04-18 21 views
6

說我寫了下面的驚喜一段代碼:「< - 」和相關的值

func = do 
    a <- Just 5 
    return a 

這是非常沒有意義的,我知道。這裏,a5,並且func返回Just 5

現在我重寫我的真棒(但無意義)功能:

func' = do 
    a <- Nothing 
    return a 

該函數返回Nothing,但到底是什麼a?沒有什麼從Nothing值中提取的,但是當我做這樣的事情的程序不發牢騷:

func'' = do 
    a <- Nothing 
    b <- Just 5 
    return $ a+b 

我只是很難看到到底發生了什麼。什麼是a?換句話說:<-究竟是呢?說它「從右側提取值並將其綁定到左側」顯然是過度簡化了它。我沒有得到什麼?

謝謝:)

+1

'<-'轉換爲'>> ='。對於'Maybe' monad,如果第一個參數(即'<--'的右邊部分)是'Nothing',則不計算其他值,而>> >> ='只返回'Nothing'。所以,要回答你的問題:執行甚至不會_reach_'a'。 – Vitus 2012-04-18 07:41:51

+0

將monad視爲容器,使用do-notation可以將標籤分配給monads中的值(如果有),然後定義適用於這些值的函數。但是提取是一種幻想 - 函數被應用於monad_中(使用'>> ='),因爲沒有從monad中提取值的一般方法。請注意,如何通過將結果_back放入monad_中來結束每個do-block,通常使用'return'。你永遠不會真的有一個變量'a',等於5. – Nefrubyr 2012-04-19 13:38:17

回答

11

讓我們試着去解釋最後一個例子的符號。

func'' = Nothing >>= (\a -> Just 5 >>= (\b -> return $ a+b)) 

現在,讓我們看看>> =是如何爲Maybe定義的。這是在前奏:

instance Monad Maybe where 
    (Just x) >>= k = k x 
    Nothing >>= k = Nothing 
    return   = Just 
    fail s   = Nothing 

所以Nothing >>= foo簡直是Nothing

+0

謝謝:)我想我不是很擅長desugaring do-notation ... – Undreren 2012-04-18 07:59:40

+1

每個foo < - bar都遵循方案欄>> =( \ foo - > ...)。現在你還可以看到爲什麼在每個do塊的末尾必須有一個表達式,或者其中一個(可能是嵌套的)lambda表達式會有一個空的函數體。也許這個鏈接將有助於:http://book.realworldhaskell.org/read/monads.html#monads.do – Sarah 2012-04-18 08:20:24

5

讓我們來看看Maybe單子的定義。

instance Monad Maybe where 
    return = Just 

    Just a >>= f = f a 
    Nothing >>= _ = Nothing 

而且desugar在功能do -notation:

func' = 
    Nothing >>= \a -> 
    return a 

的第一個參數是>>=Nothing從上面的定義可以看出,>>=只是忽略了第二個參數。所以我們得到:

func' = Nothing 

由於功能\a -> ...沒有被調用,a永遠不會被分配。所以答案是:a甚至沒有達到。


至於脫糖do -notation,下面是它是如何做一個速寫(有一個簡化我做了 - 的fail處理,即不匹配模式):

do {a; rest} → a >> do rest 

請注意,>>通常以>>=作爲a >>= \_ -> do rest(即第二個函數忽略參數)來實現。

do {p <- a; rest} → a >>= \p -> do rest 

do {let x = a; rest} → let x = a in do rest 

最後:

do {a} = a 

下面是一個例子:

main = do 
    name <- getLine 
    let msg = "Hello " ++ name 
    putStrLn msg 
    putStrLn "Good bye!" 

desugars到:

main = 
    getLine >>= \name -> 
    let msg = "Hello " ++ name in 
    putStrLn msg >> 
    putStrLn "Good bye!" 

其中t Ø使其完全爲那些誰是好奇,這裏的「正確」翻譯do {p <- a; rest}(直接從Haskell的報告採取的):

do {pattern <- a; rest} → let ok pattern = do rest 
           ok _  = fail "error message" 
          in a >>= ok 
6

的答案在於MaybeMonad實例的定義:

instance Monad Maybe where 
    (Just x) >>= k  = k x 
    Nothing >>= _  = Nothing 
    (Just _) >> k  = k 
    Nothing >> _  = Nothing 
    return    = Just 

func''翻譯爲:

Nothing >>= (\a -> (Just 5 >>= (\b -> return (a+b)))) 

從定義3210你可以看到第一個Nothing只是通過結果。

2

Nothing是不是真的「一無所有」,它實際上是東西在Maybe單子可能值:

data Maybe t = Nothing | Just t 

也就是說,如果你有Maybe t類型的某種類型t的東西,它可以有值Just x(其中xt的任何類型)Nothing;在這個意義上Maybe只是延伸t有一個更多的可能值,Nothing。 (它具有其他屬性,因爲它是一個monad,但並不真正關心我們這裏,除了的do<-的語法糖。)

1

讓我們把你的例子:

func = do 
    a <- Just 5 
    return a 

就像在其他編程語言可以將它分成兩部分,分別對應「到目前爲止所做的工作」和「尚未完成的工作」。例如Just 5

之間
a <- ... 
return a 

在許多流行的編程語言,你所期望的Just 5被塞進變量a和代碼會繼續,我們可以取得突破。

Haskell做了一些不同的事情。 「代碼的其餘部分」可以被認爲是一個函數,描述如果您有投入的價值,您將如何處理a。該功能然後應用於Just 5。但它不是直接應用。它適用於>>=適用的任何定義,具體取決於表達式的類型。對於Maybe>>=定義爲使得在處理Just X時,「其餘代碼」功能應用於X。但它也被定義爲在處理Nothing時,「代碼的其餘部分」功能被忽略,並返回Nothing

現在,我們可以解釋你的其他例子

func'' = do 
    a <- Nothing 
    b <- Just 5 
    return $ a+b 

分解成Nothing和:

a <- ... 
    b <- Just 5 
    return $ a+b 

正如我上面說的,這個代碼塊可以被認爲適用於可能的函數值爲a。但它與Nothing一起使用,在這種情況下,>>=被定義爲忽略「其餘代碼」並且僅返回Nothing。這就是你得到的結果。