首页 > 解决方案 > 制作 Ord 类的 newtype 实例

问题描述

由于 Ord 是 Eq 的子类,我发现很难理解如何创建该类的新类型实例。

我设法做到了:

    newtype NT1 = NT1 Integer

    instance Eq NT1 where 
        (NT1 x) == (NT1 y) = x == y 

    instance Ord NT1 where 
        (NT1 x) `compare` (NT1 y) = x `compare` y 

例如,如果我有一个变量x = NT1 5和变量y = NT1 5并输入 x == y 它将返回True

我也设法做到了这一点:

instance Show NT1 where
        show (NT1 n) = show n

将显示x = NT1 55而不是NT1 5

在此之后,我应该能够执行以下操作:

instance Ord NT1 where 
       (>)  (NT1 x)(NT1 y)  =  (NT1 x) >   (NT1 y)
       (<)  (NT1 x)(NT1 y)  =  (NT1 x) <   (NT1 y)
       (<=) (NT1 x)(NT1 y)  =  (NT1 x) <=  (NT1 y)
       (>=) (NT1 x)(NT1 y)  =  (NT1 x) >=  (NT1 y)

但这不起作用。如何使用 Ord 类执行此操作:

class  (Eq a) => Ord a  where
    compare              :: a -> a -> Ordering
    (<), (<=), (>=), (>) :: a -> a -> Bool
    max, min             :: a -> a -> a

?

标签: haskell

解决方案


在此之后,我应该能够执行以下操作:

instance Ord NT1 where 
       (>)  (NT1 x)(NT1 y)  =  (NT1 x) >   (NT1 y)
       (<)  (NT1 x)(NT1 y)  =  (NT1 x) <   (NT1 y)
       (<=) (NT1 x)(NT1 y)  =  (NT1 x) <=  (NT1 y)
       (>=) (NT1 x)(NT1 y)  =  (NT1 x) >=  (NT1 y)

您在这里所做的基本上是定义一组函数,其中每个函数都使用相同的参数调用自身,因此这将陷入无限循环。

实际上,例如,您在这里定义:

instance Ord NT1 where 
       (>)  (NT1 x)(NT1 y)  =  (NT1 x) >   (NT1 y)

所以这意味着你说NT1 x > NT1 y, given NT1 x > NT1 y,但当然这并没有真正做任何事情。

好消息是您不需要定义所有这些函数:Haskell 已经在Ordtypeclass 中构造了很多其他函数,所以如果我们查看文档Ord,我们会看到:

最小完整定义

compare | (<=)

所以实施compare, or(<=)就足够了。Haskell 可以基于该实现,还计算其他比较,以及min,max等。您可以实现这些,例如,如果有NT1 x < NT1 y比调用compare和检查结果是否为 更有效的方法来检查 if LT

您的实现如下:

newtype NT1 = NT1 Integer

instance Eq NT1 where 
    (NT1 x) == (NT1 y) = x == y 

instance Ord NT1 where 
    (NT1 x) `compare` (NT1 y) = x `compare` y

因此就足够了,例如:

Prelude> NT1 14 < NT1 25
True

因此正确比较了两个对象。

这也是一个简单的实现,NT1如果构造函数相同,则两个对象相等(这里只有一个构造函数),并且参数是一个简单的实现。

Ord还有一个“流行”的实现:一个对象被认为比另一个对象小,因为第一个对象的构造函数在第二个对象的构造函数之前定义,或者如果构造函数相同,则通过比较这些参数更小“按字典顺序”。

Haskell 支持这些类型的实现,您可以deriving在类型定义中使用子句:

newtype NT1 = NT1 Integer deriving (Show, Eq, Ord)

在这里,我们因此“自动”实现Eq,OrdShow类型类。因为Show它是通过首先显示构造函数的名称,然后是show参数的名称来实现的。它还在某些不明确的情况下添加了括号(尽管规则有点复杂)。

我们也可以像@DanielWagner 所说的那样自己实现这些功能:

instance Ord NT1 where 
    compare (NT1 x) (NT1 y) = compare x y
    (>)  (NT1 x)(NT1 y)  = x > y

因此,这里我们NT1使用右侧的数据构造函数调用 this ,否则我们将简单地使用相同的参数再次调用此函数。使用上面的实现,我们调用x > y, 所以(>)但是在构造函数中包含的参数上。


推荐阅读