我试图为岩石剪刀定义一种数据类型,并想出了类似的东西:
data Hand = P | S | R deriving (Show, Eq)
instance Ord Hand where
compare R P = LT
compare P R = GT
compare R S = GT
compare S R = LT
compare P S = LT
compare S P = GT
compare _ _ = EQ
在编写所有我想知道是否有任何方法来定义数据类型只是让它派生Ord然后指定
compare R P = LT
和compare P R = GT
而不是必须手动编写所有比较,对于三个元素,没关系,但每个添加的元素都会变得乏味。
答案 0 :(得分:7)
您在此处描述的是 不订单关系。订单关系是:
x
都小于或等于其本身; x
小于或等于y
且y
小于或等于x
,则x
等于{ {1}}; y
小于或等于x
且y
小于或等于y
,则{ {1}}小于或等于z
。您的定义不传递。确实:x
小于z
,S
小于R
,但R
不小于P
。因此,我强烈建议您不使用S
,因为例如排序等会使用这些不变量。
您可以做的是让它自动从P
派生:
Ord
然后定义一个函数Ord
:
data Hand = P | S | R deriving (Show, Eq, Ord)
答案 1 :(得分:3)
您可以编写此函数的通用变体:
data Hand = P | S | R deriving (Show, Eq, Ord, Bounded)
然后只需派生所需的实例:
taskNumber
答案 2 :(得分:1)
我喜欢@ freestyle的答案最好并且影响只是画一个Cirord类型类,它可能适用于任何像Pokemons等循环有序数据类型:)
class (Bounded a, Ord a) => Cirord a where
ccompare :: a -> a -> Ordering
cmax, cmin :: a -> a -> a
ccompare x y = let mima = [minBound, maxBound]
in if x `elem` mima && y `elem` mima then compare y x
else compare x y
cmax x y = if ccompare x y == LT then y else x
cmin x y = if ccompare x y == LT then x else y
data Hand = P | S | R deriving (Show, Eq, Ord, Bounded)
instance Cirord Hand
*Main> ccompare P R
GT
*Main> ccompare S R
LT
*Main> ccompare R S
GT
*Main> ccompare R P
LT
*Main> ccompare P S
LT
*Main> ccompare S P
GT