如何在Haskell中实现Ratio?

时间:2014-03-25 14:26:40

标签: haskell

这是我一段时间以来一直困惑的事情,我不知道如何能够更多地了解它。假设我有以下程序:

main :: IO ()
main = do
    x <- liftM read getLine
    y <- liftM read getLine
    print (x % y)

如果我使用输入62运行此操作,则会打印3 % 1

简化发生在什么时候(即gcd划分)?它是否在show中实施?如果是这样,那么理性的基础表示仍然是6 % 2?如果没有,那么(%)会进行简化吗?我的印象是(%)是一个数据构造函数,那么数据构造函数除了“构造”之外还会做什么呢?更重要的是,我将如何实际使用自己的数据构造函数进行类似的操作?

感谢您对此主题的任何帮助。

2 个答案:

答案 0 :(得分:17)

Ratio实际上是在GHC.Real中实现的(显然是在GHC上),定义为

data Ratio a = !a :% !a deriving (Eq)

刘海只是严格要求。如您所见,函数%不是数据构造函数,而是:%。由于您不应该直接构造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)

规则是如果运算符以冒号:开头,那么它是构造函数,否则它只是一个普通的运算符。实际上,这是Haskell标准的一部分,所有类型操作符都必须以冒号作为它们的第一个字符。

答案 1 :(得分:7)

您只需查看source即可自行查看:

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