完全有序的Ord实例用于无方向边缘?

时间:2011-09-20 03:48:41

标签: haskell

我正在尝试为无方向边创建数据类型的实例。 边缘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实例吗?

2 个答案:

答案 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