[英]How is Ratio implemented in Haskell?
This is something I have been confused about for a while and I am not sure how I can learn more about it. 这是我一段时间以来一直困惑的事情,我不知道如何能够更多地了解它。 Let's say I have the following program:
假设我有以下程序:
main :: IO ()
main = do
x <- liftM read getLine
y <- liftM read getLine
print (x % y)
If I run this with the input 6
and 2
, it will print 3 % 1
. 如果我用输入
6
和2
运行它,它将打印3 % 1
。
At what point does the simplification happen (namely the division by the gcd)? 在什么时候简化发生(即由gcd划分)? Is it implemented in
show
? 它是在
show
实施的吗? If so, then is the underlying representation of the rational still 6 % 2
? 如果是这样,那么理性的基本表示仍然是
6 % 2
? If not, then does (%)
do the simplification? 如果没有,那么
(%)
是否进行简化? I was under the impression that (%)
is a data constructor, so how would a data constructor do anything more than "construct"? 我的印象是
(%)
是一个数据构造函数,那么数据构造函数除了“构造”之外还会做什么呢? More importantly, how would I actually go about doing similar things with my own data constructors? 更重要的是,我将如何实际使用自己的数据构造函数进行类似的操作?
I appreciate any help on the topic. 我感谢任何关于这个主题的帮助。
Ratio
is actually implemented in GHC.Real
(on GHC, obviously), and is defined as Ratio
实际上是在GHC.Real
实现的(显然在GHC上),定义为
data Ratio a = !a :% !a deriving (Eq)
The bangs are just there for strictness. 刘海只是严格要求。 As you can see, the function
%
is not a data constructor, but :%
is. 如您所见,函数
%
不是数据构造函数,但是:%
是。 Since you aren't supposed to construct a Ratio
directly, you use the %
function, which calls reduce. 由于您不应该直接构造
Ratio
,因此使用%
函数,它调用reduce。
reduce :: (Integral a) => a -> a -> Ratio a
{-# SPECIALISE reduce :: Integer -> Integer -> Rational #-}
reduce _ 0 = ratioZeroDenominatorError
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y
(%) :: (Integral a) => a -> a -> Ratio a
x % y = reduce (x * signum y) (abs y)
The rule is that if an operator starts with a colon :
, then it is a constructor, otherwise it is just a normal operator. 该规则是,如果运营商是冒号命令
:
,那么它是一个构造函数,否则它只是一个普通的操作人员。 In fact, this is part of the Haskell standard, all type operators must have a colon as their first character. 实际上,这是Haskell标准的一部分,所有类型的运算符都必须以冒号作为它们的第一个字符。
You can just look at the source to see for yourself: 您可以查看源代码以便自己查看:
instance (Integral a) => Num (Ratio a) where
(x:%y) + (x':%y') = reduce (x*y' + x'*y) (y*y')
(x:%y) - (x':%y') = reduce (x*y' - x'*y) (y*y')
(x:%y) * (x':%y') = reduce (x * x') (y * y')
negate (x:%y) = (-x) :% y
abs (x:%y) = abs x :% y
signum (x:%_) = signum x :% 1
fromInteger x = fromInteger x :% 1
reduce :: (Integral a) => a -> a -> Ratio a
reduce _ 0 = ratioZeroDenominatorError
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.