通过具有不同参数数量的方程定义函数

时间:2012-01-05 16:04:05

标签: haskell

我今天注意到这样的定义

safeDivide x 0 = x
safeDivide = (/)

是不可能的。我很好奇这背后的(好)原因是什么。必须有一个非常好的(毕竟它是Haskell))。

注意:我不是在寻找上面代码的替代实现的建议,这是一个简单的例子来证明我的观点。

3 个答案:

答案 0 :(得分:26)

我认为这主要是为了保持一致,所以所有条款都可以用相同的方式阅读,可以这么说;即每个RHS在功能类型中处于相同位置。如果你允许的话,我认为会掩盖一些愚蠢的错误。

还有一个轻微的语义怪癖:假设编译器填写了这些子句,使其具有与其他子句相同数量的模式;即你的例子将成为

safeDivide x 0 = x
safeDivide x y = (/) x y

现在考虑第二行是否为safeDivide = undefined;在没有上一个条款的情况下,safeDivide将为,但由于此处执行的eta扩展,它是\x y -> if y == 0 then x else ⊥ - 因此safeDivide = undefined实际上并未定义safeDivide 1}}成为!这似乎令人困惑,足以证明禁止这些条款,IMO。

答案 1 :(得分:12)

具有多个子句的函数的含义由Haskell标准(section 4.4.3.1)通过转换为lambda和case语句来定义:

fn pat1a pat1b = r1
fn pat2a pat2b = r2

变为

fn = \a b -> case (a,b) of
  (pat1a, pat1b) -> r1
  (pat2a, pat2b) -> r2

这使得函数定义/ case语句的处理方式很好且一致,并且每个方法的含义都没有冗余和混乱地指定。

当每个子句具有相同数量的参数时,此转换才真正有意义。当然,可能还有额外的规则可以解决这个问题,但是它们会使翻译变得复杂,但是为了读者的利益,你可能不会想要定义类似的东西。

答案 2 :(得分:5)

Haskell这样做是因为它的前辈(如LML和Miranda)做到了。它没有技术上的原因;可以扩展具有较少参数的方程。但是对于不同的方程有不同数量的论证可能是一个错字而不是有意的,所以在这种情况下,我们禁止在常见情况下获得更好的错误报告的合理和罕见的东西。