我是Haskell的新手,我对以下行为感到困惑:
我有一个名为dealWithIt的函数。它看起来像这样:
dealWithIt :: (Show a) => [a] -> String
dealWithIt = foldl f ""
where f memo x = memo ++ (show x)
一切都很好,它按预期工作,它获得一个showables列表并将它们连接成一个字符串。
据我所知,只要可以将其传递给基础函数链,我是否明确指定了收到的参数并不重要。这意味着以下两个定义应该是等价的:
dealWithIt xs = foldl f "" xs
dealWithIt = foldl f ""
到目前为止一切顺利。假设我想通过模式匹配现在添加一个特殊情况:
dealWithIt [] = "Empty list :("
这就是事情变得奇怪的地方。如果我没有明确指定xs参数,我会收到以下错误:
Equations for ‘dealWithIt’ have different numbers of arguments
我可以忍受它,但对我来说真的很有趣的是,为什么Haskell无法检测到正在发生的事情并报告错误,即使这两个变体只有一个参数?
答案 0 :(得分:4)
这只是一个规则。按案例定义函数:
f p0 p1 = e0
f p2 p3 = e1
对于所有方程,必须在左侧的函数参数中具有相同数量的模式。
部分原因是为了简化语言的定义; Haskell标准根据单 case
表达式定义该函数定义:
f x0 x1 = case (x0, x1) of
(p0, p1) -> e0
(p2, p3) -> e1
现在考虑如果你能说
会发生什么f p0 p1 = e0
f p2 = e1 -- `e1` is a function
语言标准必须专门处理该案例,并将其定义为
f x0 x1 = case (x0, x1) of
(p0, p1) -> e0
(p2, _) -> e1 x1 -- Note that the argument to `e1` has to be supplied explicitly
这对于通常不明智的事情来说是一种不必要的并发症。
此外,请考虑foldr
:
foldr f z [] = z
foldr f z (x:xn) = f x (foldr f z xn)
假设您正在键入它而忘记了第一个等式的f
:
foldr z [] = z
foldr f z (x:xn) = f x (foldr f z xn)
当前规则允许捕获这样的拼写错误:编译器可以抱怨在不同的等式中有不同数量的参数。否则你会得到一些令人困惑的类型错误,这可能很难调试。 (可能您会收到错误,因为第一个等式中的z
必须与第二个等式中的f
具有相同的类型,并且第一个等式中的z
必须具有相同的类型在第二个等式中为f x (foldr f z xn)
,因此foldr
的第一个参数必须具有无限类型。无限类型错误通常无法调试。)