关于模数:%在Haskell中做什么?

What does % do in Haskell?

我习惯用%在其他语言中表示"模"。在haskell,我们必须使用mod x yx `mod` y。那么,这个符号在哈斯克尔是用来做什么的?


通过快速查看hoogle,可以看到%是一个infix函数,定义为

1
(%) :: Integral a => a -> a -> Ratio a

你可以猜到它是Data.Ratio库的一部分,它主要处理比率(即分数)。它是代码是

1
x % y = reduce (x * signum y) (abs y)

因此,给定两个积分(x,y),它返回一个不可约分数x/y。


在haskell中,我们可以像普通函数一样用各种符号(包括%)定义二进制运算符,因此您可以(在定义它的模块中)将%定义为所需的任意运算符。

作为最典型的情况,%通过data.ratio模块作为Ratio类型的构造函数提供。

在ghci上尝试下面的代码,以确保%Data.Ratio提供:

1
2
3
4
5
6
7
ghci> 3 % 9

<interactive>:1:3: error:
    Variable not in scope: (%) :: Integer -> Integer -> t
ghci> import Data.Ratio
ghci> 3 % 9
1 % 3

请记住,您可以在这些搜索引擎中搜索这些运算符和函数:

  • https://www.haskell.org/hoogle网站/
  • https://www.stackage.org网站/

实际上,我已经研究过hoogle是如何定义%的。

%中缀函数定义为

1
(%) :: Integral a => a -> a -> Ratio a

从上面的类型定义可以看出,它是Data.Ratio库的一部分,它主要处理比率(即分数)。它的代码是

1
x % y = reduce (x * signum y) (abs y)

因此,给定两个积分(x,y),它返回一个不可约分数x/y。


在Stackage Hoogle上搜索(%),似乎Data.Ratio%操作符定义为从分子和分母构造Ratio值。GHCI示例:

1
2
3
4
5
6
Prelude> :m + Data.Ratio
Prelude Data.Ratio> let x = 1 % 2
Prelude Data.Ratio> x
1 % 2
Prelude Data.Ratio> :t x
x :: Integral a => Ratio a

Data.Ratio使用%作为构造函数,但除非该类型是在Integral类型类之前定义的,否则它不能解释为什么%可供Data.Ratio使用。(当然,合格的导入允许您在多个模块中使用相同的操作员名称,因此无论哪种方式,Data.Ratio使用的%都不是真正的原因。)

但是,请注意,Integral定义了modrem函数。我怀疑%是故意被Integral排除在外的,这两个目的都是为了避免1)选择它是否应该是modrem的别名,以及2)让人们记住做出的选择。

另外,语言对%使用不同的定义,因此(%) = mod(%) = rem都有可能混淆某人。