Haskell实际上如何定义+函数?

10

在阅读Real world Haskell时,我想到了这个笔记:

ghci> :info (+)
  class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a
  ...
  -- Defined in GHC.Num
  infixl 6 +

但是Haskell如何将+定义为非本地函数呢?在某个层面上,你必须说2 + 3会变成汇编语言即机器码。


我理解这个问题是“如何在某个级别上定义+作为非本地函数,而不使用汇编原语?”另一个可能的变体是“实际的Haskell实现如何定义+?”请编辑您的问题以澄清您想要哪些答案。 - nponeccop
2个回答

21

+ 函数是重载的,对于一些类型,比如 IntDouble+ 的定义类似于:

instance Num Int where
    x + y = primAddInt x y

在这里,primAddInt是一个编译器知道并将生成机器代码的函数。

它的具体形式和工作方式取决于您所使用的Haskell实现。


6
在 GHC 中,相应的函数是 +# :: Int# -> Int# -> Int#。因此,实现类似于 I# a + I# b = I# (a +# b) - fuz

5

事实上,可以完全不使用任何本地基元来定义数字。有很多方法,但最简单的方法是:

data Peano = Z | S Peano

然后,您可以使用模式匹配为此类型定义instance Num。 数字的第二种常见表示法是使用仅函数的所谓教堂编码(所有数字都将由一些晦涩的函数表示,而+将“添加”两个函数以形成第三个函数)。确实可能存在非常有趣的编码。例如,您可以使用位序列表示[0,1)中的任意精度实数:
data RealReal = RealReal Bool RealReal | RealEnd

在GHC中,它当然是通过使用原语或FFI以机器特定的方式来定义的。


1
如果你想要可计算的算术,那么 RealReal 的定义不是很好。 - augustss
1
如果您从未计划使用任何位,则根本不必表示它们。 :) - augustss
6
假设您要查看一些位的初始段,那么在进行定义加法时会遇到麻烦,因为您无法限定前瞻来确定进位。例如,0.010101... + 0.0010101... 第一个小数点后面是什么?您必须无限远地查看才能确定它。这意味着加法无法产生结果中的任何一个位。 - augustss
你应该研究一下精确实数算术领域,这个领域已经被广泛研究。 - augustss
1
@nponeccop 位流是一种特殊的柯西序列,但不幸的是,它们不支持加法运算,比如上面由augustss演示的那样。 - Daniel Wagner
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接