我有来自99个Haskell问题的Problem 26的以下代码:
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
这里发生了什么?如何使用>>=
和>>
?
答案 0 :(得分:15)
... lambdas的片段与do块“大致相同”。它不是一个精确的翻译,因为符号添加了模式匹配失败的特殊处理。
考虑这个例子:
f xs = do
(x:_) <- Just xs
return x
g xs = Just xs >>=
\(x:_) -> return x
对于任何非空列表,这些功能都是相同的。但是f []
会返回Nothing
,而g []
会返回一个与您获得的错误非常相似的错误。
这是因为do
符号处理失败的方式不同。 Monad
类型类具有fail
函数。您正在使用列表monad,它通过返回空列表而失败。 Maybe
monad通过返回Nothing
来实现它。无论哪种方式,使用此函数处理do
表示法中的模式匹配失败,因此存在差异。
所以翻译它的正确方法是:
g xs = Just xs >>=
\xs' -> case xs' of
(x:_) -> return x
[] -> fail "some error"