在haskell

时间:2015-10-02 12:44:01

标签: haskell types

我无法找到如何在haskell中为我的数据类型实现特殊ord。我在论坛上看到它应该看起来像这样:

import Data.Set

data Cord = Cord { x :: Int
                 , y :: Int} deriving (Eq,Ord)

instance Eq Cord where
    (Cord a b) == (Cord a b) = (a==c and b==d) 

instance Ord Cord where
    compare (Cord a b) (Cord c d) = if a==c then compare (b d) else compare(a c)

我想创建一个包含2个整数的简单类型,如果第一个数字大于其他第一个数字,则一个大于另一个,如果第一个数字相等,则为第二个。我知道这种比较可以通过创建2个整数的列表来完成,但是我想要更复杂的数据类型并且无法找到指导如何使用if-s和递归定义ord的指南

谢谢你的回复!

3 个答案:

答案 0 :(得分:3)

我认为您真正的问题是您使用了deriving (Eq, Ord),这意味着您已经拥有Ord的派生类型类实例。如果你删除它并使用你的比较,它似乎很好:

data Cord = Cord { x :: Int, y :: Int }
  deriving (Eq, Show)

instance Ord Cord where
  compare (Cord a b) (Cord c d) = if a == c then compare b d else compare a c   

GHCI:

*Main> compare (Cord 4 2) (Cord 9 6)
LT
*Main> compare (Cord 3 2) (Cord 3 0)
GT
*Main> compare (Cord 2 2) (Cord 2 2)
EQ

答案 1 :(得分:1)

Ord的一个有用的事情是Monoid的实例,因此您可以像这样结合您的案例

instance Ord Coordinate where
    compare (Coord x1 x2) (Coord y1 y2) = (compare x1 y1) <> (compare x2 y2)

您可能需要import Data.Monoid才能拥有(<>)。 这个“技巧”使您能够从比较子结果的实际操作中抽象出遍历/ if-then-elsing / recursing数据结构。

如果你告诉我你的数据类型是什么 - 我可以(也许)给你更具体的提示如何做到这一点。

修改

关于Monoid事情的更多解释:

Monoid是一种数据结构,具有(associative)操作<>,允许您组合两个数据结构和具有以下属性的中性元素mempty

 x <> mempty = x
 mempty <> x = x

你能想到的最简单的例子是你的数据结构是好的旧列表[a]然后组合运算符只是列表(<>) = (++)的连接而中性元素是空列表{{1 }}

对于mempty = [],组合稍微复杂一点 - Ord会产生compare类型的内容,这只是Ordering中的一个,所以我们必须为它定义两件事成为EQ|LT|GT

Monoid

mempty = EQ LT <> _ = LT GT <> _ = GT EQ <> x = x 是抽象事物的一种非常方便的方式,所以它们是一个巧妙的伎俩。

答案 2 :(得分:0)

您可以使用您喜欢的任何函数(具有正确的签名)定义类型类的实例。

举个例子:

newtype LexInt = LexInt [Int] -- ints in reverse digit order
instance Eq LexInt where
    (==) (LexInt (l:ls)) (LexInt (r:rs)) = (l == r) && ((LexInt ls) == (LexInt rs))
    (==) (LexInt []) (LexInt []) = True
    (==) _ _ = False