2016-04-05 49 views
4

我想了解範圍如何工作在塊中。用哈斯克爾monads瞭解範圍

如果我有以下代碼:

l = [1, 2, 3] 
m = [1, 2] 

那麼這工作得很好

res = do 
    a <- l 
    b <- m 
    return (a, b) 

,並返回ml笛卡爾乘積。

要理解我嘗試以不同的形式來改寫這個範圍內(不含做塊)

我知道,做塊超過一元的操作只是語法糖,所以我試圖「unsugar」,並通過使用this並想出了這個:

res = l >>= (\a -> m) >>= (\b -> return (a, b)) 

奇怪,我得到這個錯誤Not in scope: ‘a’

任何人都可以告訴我我做錯了什麼地方,可能,範圍是如何工作的,因爲它確實看起來像do塊中的return能夠訪問的魔術?

非常感謝您

回答

12

的問題是,在你的代碼中的拉姆達的範圍是不完全正確。它應該一直延伸到表達式的結尾,而不僅僅是小計算。你的代碼應該解除爲

l >>= (\a -> m >>= (\b -> return (a, b)) 

你可以通過這種方式放棄括號,這使得它更愉快。

l >>= \a -> m >>= \b -> return (a, b) 

但這種模糊含義。如果你想要很痛苦的明確,我們可以轉換爲前綴符號,並說

bind a f = a >>= f 
bind l (\a -> bind m (\b -> return (a, b)) 

也許剝離一些操作員糖幫助。

請注意>> ='s巢裏面的 lambda,不在其周圍。這確保a保持在範圍內。實際上,這種嵌套有點用手寫出來,這是寫作的動力之一:)

+0

對不起,有兩個很好的答案,這是第一個。 我現在明白了。這一切都有道理,因爲現在對於所有不同的a都有一個lambda,這就解釋了爲什麼我對這段代碼感到困惑。 非常感謝你(你們倆) –

7

問題在於括號。你寫

res = l >>= (\a -> m) >>= (\b -> return (a, b)) 

,但你需要的是

res = l >>= (\a -> m >>= (\b -> return (a, b))) 

這也可以寫成

res = l >>= \a -> m >>= \b -> return (a, b) 

您在結束了lambda表達式結合a過早,然後試圖用a