haskell 如何创建Eq和Ord的自定义函数示例

sbtkgmzw  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(199)

我已经实现了一个有理数的归一化函数normaliseRat::Rat -> Rat,这样所有的Rat 2 4,Rat(-1)(-2)和Rat 1 2都被转换为相同的内部表示。此外,实现了一个函数Rat::Rat-> Rat,给定两个整数,返回一个归一化的Rat。注意:我使用包含函数gcd的Prelude来计算两个整数的最大公约数。

gcd' :: Integer -> Integer -> Integer
gcd' a b = if b == 0 then a else gcd' b (a `mod` b)

data Rat = Rat Integer Integer

normaliseRat :: Rat -> Rat
normaliseRat (Rat num den) =
    let commonDivisor = gcd' (abs num) (abs den)
        num' = num `div` commonDivisor
        den' = den `div` commonDivisor
    in Rat (if den < 0 then (-num') else num') (abs den')

createRat :: Integer -> Integer -> Rat
createRat num den = normaliseRat (Rat num den)

-- Adding the Show instance for Rat
instance Show Rat where
    show (Rat num den) = show num ++ "/" ++ show den

字符串
这个程序给出了预期的结果。像:

ghci>createRat 2 4
ghci> rat1
1/2


现在我想让Rat成为Eq和Ord的一个示例。当然,Rat 2 4 == Rat 1 2应该计算为True。

mzsu5hc0

mzsu5hc01#

一种选择是确保Rat 2 4不是一个可以构造的值。通过只公开保留规范化的API部分来实现这一点。例如:

module Rat (
    Rat, -- expose the type, but not the data constructor
         -- (compare an export of Rat(Rat) or Rat(..) which would export both)
    createRat,
    )

-- because rationals are always created already-reduced, the
-- derived Eq instance is good enough
data Rat = Rat Integer Integer deriving Eq

createRat :: Integer -> Integer -> Rat
createRat = undefined

-- reduction isn't enough if you want the usual ordering on
-- rationals, so we need to implement this one ourselves
instance Ord Rat where compare (Rat n d) (Rat n' d') = undefined

字符串
这是一种相当标准的技术,您可以使用“smartconstructor”作为搜索词来查找更多的资源。
顺便说一下,我建议派生Show示例。如果你想用一种更漂亮的方式来显示有理数,导出一个专门的函数,名为showRat或类似的。这也是一个常见的做法。

ymdaylpp

ymdaylpp2#

我们知道两个分数 a/Bc/d 是相等的,如果 a×d = c×B(假设因子不为零),那么我们可以将Eq示例实现为:

instance Eq Rat where
    Rat a b == Rat c d = a * d == b * c

字符串
我把Ord的示例留作练习。这会更复杂,因为它的参数也可以是负的。

相关问题