我无法找到如何在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的指南
谢谢你的回复!
答案 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