Haskell 用具有不同参数数的方程定义函数

Haskell 用具有不同参数数的方程定义函数,haskell,Haskell,我今天注意到这样一个定义 safeDivide x 0 = x safeDivide = (/) 这是不可能的。我只是好奇这背后的(好)原因是什么。一定有一个非常好的(毕竟是哈斯克尔:)) 注意:我不是在寻找对上述代码的替代实现的建议,这是一个简单的例子来证明我的观点。我认为这主要是为了一致性,所以可以说,所有条款都可以以相同的方式阅读;i、 e.每个RHS在功能类型中处于相同位置。我想如果你也允许的话,会掩盖很多愚蠢的错误 还有一点语义上的怪癖:假设编译器填充了这样的子句,使其与其他子句具有

我今天注意到这样一个定义

safeDivide x 0 = x
safeDivide = (/)
这是不可能的。我只是好奇这背后的(好)原因是什么。一定有一个非常好的(毕竟是哈斯克尔:))


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

我认为这主要是为了一致性,所以可以说,所有条款都可以以相同的方式阅读;i、 e.每个RHS在功能类型中处于相同位置。我想如果你也允许的话,会掩盖很多愚蠢的错误

还有一点语义上的怪癖:假设编译器填充了这样的子句,使其与其他子句具有相同数量的模式;i、 你的榜样将成为

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

现在考虑第二行是否是<代码>安全划分=未定义的< /代码>;如果没有前面的子句,

safeDivide
将是,但是由于这里执行了eta扩展,它是
\x y->如果y==0,那么x else⊥-因此
safeDivide=undefined
实际上没有将
safeDivide
定义为
!这似乎令人困惑,足以证明禁止此类条款是合理的。

Haskell标准通过翻译为lambda和
case
语句定义了具有多个条款的函数的含义:

fn pat1a pat1b = r1
fn pat2a pat2b = r2
变成

fn = \a b -> case (a,b) of
  (pat1a, pat1b) -> r1
  (pat2a, pat2b) -> r2
这样做是为了使函数定义/case语句的处理方式是好的和一致的,并且每个语句的含义不会被重复和混淆地指定


只有当每个子句具有相同数量的参数时,这种翻译才真正有意义。当然,可能会有额外的规则来解决这一问题,但它们会使翻译变得复杂而毫无益处,因为为了读者的利益,你可能无论如何都不想定义这样的事情。

哈斯凯尔这样做是因为它的前任(如LML和米兰达)这样做了。没有技术上的原因,它必须是这样的;具有较少参数的方程可以展开。但是,对于不同的方程有不同数量的参数可能是一个输入错误,而不是故意的,因此在这种情况下,我们禁止一些明智的做法&在普通情况下很少能得到更好的错误报告

所以没有更深层次的技术原因了吗?谢谢你的代码格式编辑:),从现在开始就可以了。我花了一段时间才弄明白为什么是const(const\bot),但现在我明白了。@aelguindy:是的,我编辑了我的答案,希望能澄清一点-
与常量⊥
特别棘手,因为它们只能用
seq
来区分。很高兴我能帮上忙:)如果我早点打刷新。谢谢你称之为“安全”?让它返回一个
可能
或其他东西,或抛出一些已知的异常,或将其用于一个
新类型
,该类型仅适用于您视为L²希尔伯特空间(即仅定义的模零集)成员的非退化函数;那是安全的。仅仅为所有的
fractive
实例定义
x/0=x
是非常不规范的嗯,这可能只是一个例子。+1哇,多年来一直在使用Haskell,从未注意到这样的定义是不允许的@leftaroundabout
safeDivide x 0=无;safeDivide=Just.:(/)
better?:)@丹伯顿,看起来好多了。你,虽然…@leftaroundabout是的,这就是xD定义一个真正“安全”的版本的要点,并且仍然存在相同的问题。