2014-10-16 8 views
1

Скажем, у меня есть тип данных, представляющий колода покерных карт, как такКак реализовать пользовательский заказ для типов данных в Haskell?

data Suit = Clubs | Spades | Hearts | Diamonds deriving (Eq) 

instance Show Suit where 
    show Diamonds = "♦" 
    show Hearts = "♥" 
    show Spades = "♠" 
    show Clubs = "♣" 

data Value = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace deriving (Eq, Ord) 

data Card = Card { 
     value :: Value 
    , suit :: Suit 
    } deriving (Eq, Ord) 

экземпляр Show Card, где шоу (Card против) = показать s ++ показать v

Haskell помогает мне уже много, позвольте мне получить Eq и Ord без явного указания этих отношений. Это особенно полезно, потому что я хочу использовать Ord, чтобы в конечном счете сравнить стоимость двух рук в соответствии с правилами покера.

Теперь в Покере костюмы не имеют особого значения с точки зрения заказа. Поэтому я попытался

instance Ord Suit where 
    compare Clubs Spades = EQ 
    compare Clubs Hearts = EQ 
    compare Clubs Diamonds = EQ 
    compare Spades Hearts = EQ 
    compare Spades Diamonds = EQ 
    compare Hearts Diamonds = EQ 

Это уже немного многословным ... и это даже не работает:

*P054> a 
♠A 
*P054> b 
♣A 
*P054> a < b 
*** Exception: P054.hs:(12,9)-(17,36): Non-exhaustive patterns in function compare 

Так как я могу правильно определить порядок на Suit, что отражает тот факт, что все костюмы равны?

ответ

7

Вам не хватает нескольких комбинаций, например. все с Clubs с правой стороны. Если все равны, каковы возможные результаты compare, независимо от ввода? Существует только один: EQ. Поэтому мы не должны даже смотреть на a или b:

instance Ord Suit where 
    compare _ _ = EQ 

Однако, что Ord экземпляр довольно бесполезно. В качестве альтернативы вы можете создать собственный экземпляр для Card,

instance Ord Card where 
    compare a b = compare (value a) (value b) 
    -- compare = compare `on` value -- using `on` from Data.Function 
    -- compare = comparing value -- using `comparing` from Data.Ord 
+1

Определение такого экземпляра, вероятно, плохой дизайн. Не так много людей ожидали бы, что экземпляр «Ord» будет определен как 'const (const EQ)'. Если сравнение между Suits не имеет смысла, экземпляр Ord просто не существует. Если костюм не влияет на порядок карты, как сказал OP, то экземпляр Ord для * Card * должен просто игнорировать иск: 'compare = Data.Ord.comparing val' – user2407038

+0

@ user2407038 Я бы принял ваш комментарий в качестве ответа , –

+0

@Zeta Ah ... редактирование. В этом есть смысл :) –