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

问题描述 投票:0回答:2

我为有理数实现了归一化函数 normaliseRat :: Rat -> Rat,以便所有 Rat 2 4、Rat (-1) (-2) 和 Rat 1 2 都转换为相同的内部表示。此外,还实现了一个函数 createRat :: Integer -> Integer -> Rat,给定两个 Integers,返回一个标准化的 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。

haskell instance typeclass haskell-platform rational-number
2个回答
1
投票

一种选择是确保

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

这是一种相当标准的技术,您可以使用“智能构造函数”作为搜索词找到更多资源。

顺便说一句,我建议派生您的

Show
实例。如果您想要一种更漂亮的有理数显示方式,请专门为此导出一个函数,名为
showRat
或类似函数。这也是一种常见做法。


0
投票

我们知道,如果 a×d = c×b(假设分母不为零),两个分数 a/bc/d 相等,因此我们可以将

Eq
实例实现为:

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

我将

Ord
的实例留作练习。这会更复杂,因为分母也可以是负数。

© www.soinside.com 2019 - 2024. All rights reserved.