我正在尝试为无方向边创建数据类型的实例。 边缘1 2 ==边缘2 1(即边缘从1到2与边缘从2到1相同,方向无关紧要)。
以下是数据类型,Eq实例和Ord实例尝试的示例:
data Edge = Edge Int Int deriving Show
instance Eq Edge where
(Edge x1 y1) == (Edge x2 y2) = ((x1 == x2 && y1 == y2) || (x1 == y2 && y1 == x2))
instance Ord Edge where
compare e1@(Edge x1 y1) e2@(Edge x2 y2) = if e1 == e2
then EQ
else ????
在这种情况下,知道如何获得totally ordered Ord实例吗?
答案 0 :(得分:6)
我的答案与托马斯的答案相似,但我建议您在构建边缘时进行标准化。
mkEdge :: Int -> Int -> Edge
mkEdge x y | x <= y = Edge x y
| otherwise = Edge y x
现在您知道具有较小索引的顶点首先出现,deriving (Eq, Ord)
实例将完全按照您的意愿执行。您只需确保只使用mkEdge
“智能构造函数”创建边(您可以通过将Edge
放在模块中而不导出Edge
构造函数来实现此目的。)
答案 1 :(得分:3)
只需将边缘连接的顶点视为无序集 (巧合的是卡片2)而不是两个单独的元素 以任意顺序:
instance Ord Edge where
compare e1@(Edge x1 y1) e2@(Edge x2 y2) = compare (sort [x1,y1]) (sort [x2,y2])
甚至使用实际集:
data EdgeS = EdgeS (Set Int) deriving (Show, Eq)
instance Ord EdgeS where
compare (EdgeS a) (EdgeS b) = compare a b
甚至可以派生此实例(对于Eq
)。如果您愿意,可以创建一个特殊的构造函数:
mkEdge : Int -> Int -> EdgeS
mkEdge a b = EdgeS (S.fromList [a,b])
还有一些测试:
> compare (mkEdge 1 2) (mkEdge 2 1)
EQ
> compare (mkEdge 1 2) (mkEdge 3 1)
LT
> compare (mkEdge 1 2) (mkEdge 1 3)
LT