2014-03-28 76 views
13

我有以下代碼的99個哈斯克爾問題Problem 26爲什麼當我試圖解除它時,我的Haskell do-notation會打破?

combinations :: Int -> [a] -> [[a]] 
combinations 0 _ = return [] 
combinations n xs = do y:xs' <- tails xs 
         ys <- combinations (n-1) xs' 
         return (y:ys) 

上面的代碼按預期工作。下面是我的主要功能和打印效果:

main = print $ combinations 2 "abcd" 
-- Prints: ["ab","ac","ad","bc","bd","cd"] 

作爲一個學習鍛鍊我試圖"desugar" the do-notation像這樣:

combinations :: Int -> [a] -> [[a]] 
combinations 0 _ = return [] 
combinations n xs = tails xs >>= \(y:xs') -> 
        do 
         ys <- combinations (n-1) xs' 
         return (y:ys) 

這將編譯,但在運行時提供了以下錯誤:

PatternMatchFail: /home/.../test.hs:(46,34)-(49,37): Non-exhaustive patterns in lambda 

這是怎麼回事?我怎樣才能用>>=>>代替do not notation?

回答

15

Haskell Wikibook

...與lambda表達式的片段是 「大致相當於」 到DO塊。它不是一個確切的翻譯,因爲這個符號增加了模式匹配失敗的特殊處理。

考慮這個例子:

f xs = do 
     (x:_) <- Just xs 
     return x 

g xs = Just xs >>= 
     \(x:_) -> return x 

對於任何非空列表,這些功能是相同的。但是f []返回Nothingg []返回的錯誤非常類似於您正在獲取的錯誤。

這是因爲do表示法處理故障的方式不同。 Monad typeclass具有fail函數。您正在使用列表monad,通過返回一個空列表失敗。 Maybe monad通過返回Nothing來實現它。無論採用哪種方式,do表示法中的模式匹配失敗都是使用此函數處理的,因此有所不同。

所以正確的方法來翻譯這將是:

g xs = Just xs >>= 
     \xs' -> case xs' of 
       (x:_) -> return x 
       [] -> fail "some error" 
+0

作爲一個初學者,我覺得現在的「它只是語法糖」是有害的,所有這些說法。我知道這在技術上是真實的,但我已經多次向我提過,符號僅僅是限制>> =和>>我必須寫的數量。 – Buttons840

+3

@ Buttons840它僅僅是一種便利,只是比你想象的多一點而已。 –

+2

@ Buttons840它_is_語法糖。沒有符號,它不會做任何你無法做到的魔法。 – Cubic

相關問題