当我在Haskell上运行此代码时:
[2] <= [1,5]
我弄错了。
但是,当我运行此命令时:
data T = A | B | C T T deriving (Eq,Ord)
A <= B && B <= C A A
我得到了。
这是为什么?出于相同的原因[2] <[1,5]也是,B <= C A A不应该为假吗?
答案 0 :(得分:7)
Haskell report指定了自动派生实例的外观:
10.1
Eq
和Ord
的派生实例由的派生实例自动引入的类方法
Eq
和Ord
是(==)
,(/=)
,compare
,(<)
,(<=)
,(>)
,(>=)
,max
和min
。 后七个运算符的定义如下 以字典方式比较他们的论点 给定构造函数集,数据类型中包含较早的构造函数 声明的数量要小于后来的声明。例如,对于
Bool
数据类型,我们有(True > False) == True
。派生的比较始终从左向后遍历构造函数 对。这些示例说明了此属性:
(1,undefined) == (2,undefined) => False (undefined,1) == (undefined,2) => _|_
类
Eq
和Ord
的所有派生操作都严格 论点。例如,False <= _|_ is _|_
即使False
是Bool
类型的第一个构造函数。
因此,Haskell将在此处实现一个Ord
函数,其中无论参数如何,具有数据构造函数A
的对象将小于具有数据构造函数B
的对象和一个对象使用数据构造函数B
的对象小于使用数据构造函数C
的对象。这是因为在定义A
之前先定义B
。
仅在数据构造函数相同的情况下,才按字典顺序对参数进行比较:因此首先比较两个对象的第一个参数,如果不相等,则是比较的结果(如果它们相等),然后我们比较第二个参数,依此类推。
因此对于您的T
类型,这些实现为:
instance Ord T where
(<=) A A = True
(<=) A B = True
(<=) A (C _ _) = True
(<=) B C = True
(<=) B (C _ _) = True
(<=) (C xa ya) (C xb yb) = xa <= xb || (xa == xb && ya <= yb)
(<=) _ _ = False
如果列表定义为:
data [] a = [] | (:) a ([] a)
然后,该定义也遵循列表的顺序,因为空列表小于非空列表,并且如果我们比较两个非空列表,我们首先比较第一个元素( “ cons”数据构造函数),然后在头部相等的情况下,比较尾巴(“ cons”构造函数的第二个参数)。因此,自动推导应为:
import Data.Monoid((<>))
instance Ord ([] a) where
compare [] [] = EQ
compare [] (_:_) = LT
compare (_:_) [] = GT
compare (ha:ta) (hb:tb) = compare ha hb <> compare ta tb
此处(<>)
的{{1}}运算符采用左元素,如果它不等于Ordering
,则采用右元素。
答案 1 :(得分:5)
如果一个自动生成的Ord
实例的构造函数在构造函数列表中的另一个值之前,则它将比另一个值小。如果构造函数相同,则将按字典顺序成对比较元素。如果我们假设Ord
位于[]
之前,则列表的:
实例的行为相同。
[2] <= [1,5]
为假的原因是[2]
(又名2 : []
)和[1,5]
(又名1:5:[]
)都使用相同的构造函数,因此将比较2
和1
,并且2
大于1
。
此原因根本不适用于B <= C A A
。 B
和C A A
不使用相同的构造函数,因此B
获胜是因为它在构造函数列表中的C
之前。