想一想,您的代码将如何转换为使用与case 的显式模式匹配?
howMany :: a -> [a] -> Int
howMany a b = case b of
[] -> 0 -- case 1
(a : xs) -> 1 + howMany a xs -- case 2
(x : xs) -> 0 + howMany a xs -- case 3
-- case 2 中的a 是一个全新的变量,完全独立于作为howMany 的形式参数的外部a。它可以用任何其他名称命名,例如
howMany :: a -> [a] -> Int
howMany a b = case b of
[] -> 0 -- case 1
(x : xs) -> 1 + howMany a xs -- case 2
(x : xs) -> 0 + howMany a xs -- case 3
现在我们也清楚地看到了之前的真实情况——案例 2 和案例 3 是一回事。
但这不是我们想要的。我们想区分x==a 的情况和它的否定。
解决方案就是明确我们的意图:
howMany :: Eq a => a -> [a] -> Int
howMany a b = case b of
[] -> 0 -- case 1
(x : xs)
| x==a -> 1 + howMany a xs -- case 2
(x : xs) -> 0 + howMany a xs -- case 3
上面可以用 lambda 表示法进一步翻译为
howMany :: Eq a => a -> [a] -> Int
howMany = \a -> (\b -> case b of
[] -> 0 -- case 1
(x : xs)
| x==a -> 1 + howMany a xs -- case 2
(x : xs) -> 0 + howMany a xs ) -- case 3
这就是为什么在 Haskell 中不允许使用非线性模式的原因——因为函数的参数是一个一个的模式匹配,而不是一致的。
这就是另一个答案中的“匹配,不统一”技术评论的意思。 inner lambda 本身就是一个 Haskell 值,独立存在。但是,如果要区分其参数变量名称,则必须根据某个外部环境中的某个其他变量做出不同的行为——不,要不同?那是不行的。