制作Ord类的newtype实例

che*_*ire 2 haskell

由于Ord是Eq的一个子类,我发现很难理解如何使该类的newtype实例看起来像.

我设法做到了这一点:

    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 
Run Code Online (Sandbox Code Playgroud)

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

我还设法做到了这一点:

instance Show NT1 where
        show (NT1 n) = show n
Run Code Online (Sandbox Code Playgroud)

whill显示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)
Run Code Online (Sandbox Code Playgroud)

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

class  (Eq a) => Ord a  where
    compare              :: a -> a -> Ordering
    (<), (<=), (>=), (>) :: a -> a -> Bool
    max, min             :: a -> a -> a
Run Code Online (Sandbox Code Playgroud)

Wil*_*sem 7

在此之后,我应该能够做到这样的事情:

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)
Run Code Online (Sandbox Code Playgroud)

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

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

instance Ord NT1 where 
       (>)  (NT1 x)(NT1 y)  =  (NT1 x) >   (NT1 y)
Run Code Online (Sandbox Code Playgroud)

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

好处是你不需要定义所有这些函数:Haskell已经在Ord类型类中构建了许多其他函数,所以如果我们看一下文档Ord,我们会看到:

最小的完整定义

compare | (<=)
Run Code Online (Sandbox Code Playgroud)

所以实施compare,或者(<=)就足够了.哈斯克尔可以基于该实现,也计算其他的比较,以及min,max等你实现这些,例如,如果有更有效的方法来检查,如果NT1 x < NT1 y不是调用compare和检查,如果结果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
Run Code Online (Sandbox Code Playgroud)

因此就足够了,例如:

Prelude> NT1 14 < NT1 25
True
Run Code Online (Sandbox Code Playgroud)

从而正确地比较两个对象.

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

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

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

newtype NT1 = NT1 Integer deriving (Show, Eq, Ord)
Run Code Online (Sandbox Code Playgroud)

在这里,我们因此"自动"执行Eq,OrdShow类型类.因为Show它是通过首先显示构造函数的名称,后跟show参数的名称来实现的.它还在某些情况下添加了括号(尽管规则稍微复杂一些).

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

instance Ord NT1 where 
    compare (NT1 x) (NT1 y) = compare x y
    (>)  (NT1 x)(NT1 y)  = x > y
Run Code Online (Sandbox Code Playgroud)

在这里,我们这样做不是与调用该NT1右侧数据构造,因为否则我们就简单地同样具有相同的参数调用此函数.通过上面的实现,我们调用x > y,(>)但是在构造函数中包含的参数.

  • ...如果你真的想要出于任何原因自己实现所有`Ord`方法,你可以`(>)(NT x)(NT y)=(>)xy`(右边没有`NT`包装器).或者,按照预期的方式使用中缀符号,`NT x> NT y = x> y`. (3认同)