这是我的数据结构
data Ex =
P String
| (:←) Ex
它具有p == ←←p
的属性。我的自定义Eq和Ord实例尝试定义它们。但是,我看到test3(从[p,←←p,←p]创建的集合)和test4(从[p,←p,←←p]创建的集合)的结果不一致。结果如下图所示:
*Test> test3
fromList [←q,←←q]
*Test> test4
fromList [q,←q,←←q]
请注意,test3和test4仅在创建集合的元素顺序上有所不同。然而,结果有所不同。
我认为使用Data.Set.fromList创建集合的顺序并不重要。有人可以帮助我找到我的Eq或Ord实例错误吗?以下完整代码,使用GHC 8.4.3编译。
module Test where
import Data.Set as S
data Ex =
P String
| (:←) Ex
instance Show Ex where
show (P s) = s
show ((:←) e) = "←" ++ (show e)
instance Eq Ex where
(P s1) == (P s2) = s1 == s2
(:←) e1 == (:←) e2
| e1 == e2 = True
| otherwise = False
e1 == (:←) e2
| e1 == e2 = False
| (:←) e1 == e2 = True
| otherwise = False
(:←) e1 == e2
| e1 == e2 = False
| e1 == (:←) e2 = True
| otherwise = False
elength :: Ex -> Int
elength (P s) = length s
elength ((:←) e) = elength e + 1
instance Ord Ex where
compare e1 e2
| e1 == e2 = EQ
| otherwise = if (elength e1) <= (elength e2) then LT
else GT
-- Check that ←q == ←←q
test2 = S.fromList [(:←) ((:←) (P "q")), P "q"]
-- output should be : {←←q, ←q}
test3 = S.fromList [P "q", (:←) ((:←) (P "q")), (:←) (P "q")]
-- output should be same as that of test3 : {←←q, ←q}
test4 = S.fromList [P "q", (:←) (P "q"), (:←) ((:←) (P "q"))]
编辑:
请注意,如果我修改elength
定义来处理这种情况,则不一致之处消失了。
elength ((:←) ((:←) e)) = elength e
在elength
和==
的情况下,也许我的q
度量和←←q
的定义不一致。我仍然想知道他们到底在哪里出错
答案 0 :(得分:6)
您的情商实例在我看来确实很奇怪。我会一次取消两个被取消的配对,而不是零散的:
instance Eq Ex where
(P s1) == (P s2) = s1 == s2
((:←) e1) == (:←) e2 = e1 == e2
e1 == (:←) ((:←) e2) = e1 == e2
(:←) ((:←) e1) == e2 = e1 == e2
_ == _ = False
也许这等于您所写的内容;很难说出来,因为您的模式匹配与您的目标不太吻合。
您的Ord实例也是一个问题,因为您没有定义一致的顺序。对于x y z
的任何项目集,其中x < y && y < z
应该是x < z
。但是,根据您的规则,有一些简单的反例:
x = P "a"
y = (P "b" :←)
z = ((P "a" :←) :←)
尽管x == z
在y
之间,但在这里。{p1
解决这两个问题的一种方法是编写一个simplify
函数,该函数删除所有成对的取消构造函数,并在Eq
和Ord
实例中使用该函数。简化每个参数,以便您知道它们各自具有0或1个否定级别。从这里开始,Eq
很简单,定义Ord
之前您需要做的就是确定一个负值是否小于或大于一个非负值。您无法选择它们相等,因为这再次破坏了传递性。
如果您确实写了simplify
,那么每次触摸这些对象之一时,调用简化会浪费很多工作,因为您会立即放弃简化。我选择不为该类型导出构造函数,而是提供一个在返回值之前进行简化的智能构造函数。然后,消费者将知道一切都被否定一次或根本没有否定。