【问题标题】:Why is Haskell unable to resolve the number of arguments automatically? [duplicate]为什么 Haskell 无法自动解析参数数量? [复制]
【发布时间】:2015-11-17 18:33:07
【问题描述】:

我是 Haskell 的新手,对以下行为感到困惑:

我有一个函数,叫做 dealWithIt。它看起来像这样:

dealWithIt :: (Show a) => [a] -> String
dealWithIt = foldl f ""
  where f memo x = memo ++ (show x)

一切都好,它按预期工作,它获取一个可显示的列表并将它们连接成一个字符串。

据我所知,我是否明确指定接收的参数并不重要,只要它可以传递给底层函数链即可。这意味着以下两个定义应该是等价的:

dealWithIt xs = foldl f "" xs
dealWithIt = foldl f ""

到目前为止一切顺利。假设我现在想通过模式匹配添加一个特殊情况:

dealWithIt [] = "Empty list :("

这就是事情变得奇怪的地方。如果我没有明确指定 xs 参数,我会收到以下错误:

Equations for ‘dealWithIt’ have different numbers of arguments

我可以接受它,但我真的很感兴趣,为什么 Haskell 无法检测到正在发生的事情并报告错误,即使两个变体都采用一个参数?

【问题讨论】:

  • dealWithIt = foldl f "" 已经指定了所有可能参数的行为。用另一个参数再次定义它有什么意义?
  • 添加特殊情况与处理所有可能的参数无关。
  • 编译器抛出的错误信息说清楚了。这些是不同的功能。比较他们的签名。如果你需要处理 special 参数,你可以使用参数模式匹配但保持相同的类型。或使用警卫,或 if/case 条件。
  • 但这正是让我感到困惑的地方,因为我的函数的两个变体具有相同的签名并接受相同类型的单个参数。那么错误来自哪里?
  • 这是一个非常合理的问题。编译器当然可以用更少的参数扩展方程。我相信这只是一个设计选择来禁止它,因此在意外忘记参数而不是神秘类型错误时提供更好的错误消息。当然,这种设计可以反对——这是一个偏好问题。

标签: haskell


【解决方案1】:

这只是一个规则。一个函数的case定义:

f p0 p1 = e0
f p2 p3 = e1

对于所有方程,左侧的函数参数中的模式数量必须相同。

部分是为了简化语言的定义; Haskell 标准根据 single 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 的第一个参数必须具有无限类型。无限类型错误通常很难调试。)

【讨论】:

  • 即使f x y = somethingWith x yf = \x y -> somethingWith x y 的语法糖,本身也是f = \x -> (\y -> somethingWith x y) 的糖,等等。意识到在某种程度上,Haskell 只存在于函数、应用程序(饱和) 构造函数调用和数据解构。
猜你喜欢
  • 1970-01-01
  • 2015-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-18
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
相关资源
最近更新 更多