模式 vs. 守卫:否则不匹配?

4
以下两个函数在输入空字符串时有不同的行为:
guardMatch l@(x:xs) 
    | x == '-'        = "negative " ++ xs
    | otherwise       = l

patternMatch ('-':xs) = "negative " ++ xs
patternMatch l        = l

以下是我的输出:

*Main> guardMatch ""
"*** Exception: matching.hs:(1,1)-(3,20): Non-exhaustive patterns in function guardMatch

*Main> patternMatch ""
""

问题:为什么“otherwise”不能捕获空字符串?
3个回答

13

otherwise出现在模式l@(x:xs)中,只能匹配非空字符串。可能看到这个(有效地)转换为内部表示会有所帮助:

guardMatch   l = case l of
                   (x  :xs) -> if x == '-' then "negative " ++ xs else l
patternMatch l = case l of
                   ('-':xs) ->                  "negative " ++ xs
                   _        ->                                         l

(实际上,我认为 if 被翻译成了 case + guard,而不是相反的。)


如果我没记错的话,“if”应该是按照你所说的翻译的。 - fuz

9

在模式匹配后,守卫语句才会被执行。也就是说,只有当模式匹配成功时,守卫语句才会被尝试执行。在您的情况下,模式(x:xs)排除了空字符串,因此守卫语句不会被尝试执行,因为模式匹配失败了。


3
其他两个回答当然是正确的,但这里还有一种思考方式:如果你写了这个呢?
guardMatch l@(x:xs) 
    | x == '-'        = "negative " ++ xs
    | otherwise       = [x]

你会期望 guardMatch "" 是什么?


好观点!正如上面的答案所教给我的那样,(x:xs)模式只匹配非空列表。 - Vladimir Bychkovsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接