【问题标题】:Defining a function by equations with different number of arguments通过具有不同数量参数的方程定义函数
【发布时间】:2012-02-03 11:02:33
【问题描述】:

我今天注意到这样的定义

safeDivide x 0 = x
safeDivide = (/)

不可能。我只是好奇这背后的(好的)原因是什么。一定有一个非常好的(毕竟是 Haskell :))。

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

【问题讨论】:

  • 你称之为“安全”?让它返回 Maybe 或其他东西,或抛出一些已知异常,或在 newtype 上使用它,专门用于您视为成员的非退化函数,例如L² Hilbert 空间(即仅定义模空集);那将是安全的。仅仅为所有Fractional 实例定义x/0=x ad hoc 是非常不规范的! ——嗯,这可能只是一个例子。
  • +1 哇,使用 Haskell 很多年了,从来没有注意到这样的定义是不允许的!
  • @leftaroundabout safeDivide x 0 = Nothing; safeDivide = Just .: (/) 更好? :)
  • @DanBurton 看起来更好。不过你can't define it this way...
  • @leftaroundabout 是的,这就是 xD 定义一个实际上“安全”的版本的要点,并且仍然存在同样的问题。

标签: haskell


【解决方案1】:

我认为这主要是为了保持一致性,以便所有从句都可以以相同的方式阅读,可以这么说;即每个 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 定义为 !这似乎足以令人困惑,足以证明禁止此类条款是合理的,IMO。

【讨论】:

  • 那么没有更深层次的技术原因吗?
  • 感谢代码格式编辑 :),从现在开始会这样做。我花了一段时间才明白为什么它是 const (const \bot),但现在我明白了。
  • @aelguindy:是的,我已经编辑了我的答案,希望能澄清一点——const ⊥ 尤其棘手,因为它们只能用seq 区分。很高兴我能帮忙:)
  • 如果我早点刷新.. :)。谢谢!
【解决方案2】:

具有多个子句的函数的含义由 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语句的处理方式很好且一致,并且每个的含义都没有被重复和混淆。

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

【讨论】:

    【解决方案3】:

    Haskell 这样做是因为它的前辈(如 LML 和 Miranda)就是这样做的。没有技术原因必须是这样的;参数较少的方程可以进行 eta 扩展。但是对于不同的方程有不同数量的参数可能是一个错字而不是故意的,所以在这种情况下,我们禁止一些明智和罕见的东西,以便在常见情况下获得更好的错误报告。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-09
      • 1970-01-01
      • 2016-01-04
      • 2020-07-19
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多