Haskell循环Ord关系

时间:2017-11-07 09:49:47

标签: haskell algebraic-data-types

我试图为岩石剪刀定义一种数据类型,并想出了类似的东西:

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 = LTcompare P R = GT而不是必须手动编写所有比较,对于三个元素,没关系,但每个添加的元素都会变得乏味。

3 个答案:

答案 0 :(得分:7)

您在此处描述的是 订单关系。订单关系是:

  1. 自反,所有值x都小于或等于其本身;
  2. 反对称:如果x小于或等于yy小于或等于x,则x等于{ {1}};
  3. transitive :如果y小于或等于xy小于或等于y,则{ {1}}小于或等于z
  4. 您的定义传递。确实:x小于zS小于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