[Haskell-beginners] Ord and Eq instances for complex types

Daniel Fischer daniel.is.fischer at googlemail.com
Wed Oct 19 01:01:38 CEST 2011


On Wednesday 19 October 2011, 00:27:19, Mike Meyer wrote:
> On Tue, Oct 18, 2011 at 2:47 PM, Daniel Fischer <
> 
> daniel.is.fischer at googlemail.com> wrote:
> > On Tuesday 18 October 2011, 23:13:03, Mike Meyer wrote:
> > > I'm working on a problem dealing with poker hands, and need to rank
> > > them. The Ord instance seems like a natural for this, but the code
> > > came out with a lot of repetitions in it.
> > > 
> > > 
> > > Is there some third alternative I've overlooked that combines the
> > > best features of both approaches?
> > > 
> > >   Thanks,
> > >   <mike
> > 
> > Well, you could use record syntax in the Hand type to avoid defining
> > cards in the Eq instance,
> > 
> > data Hand
> > 
> >    = HighCard { cards :: [Card] }
> >    
> >    | PairOf { rank :: Rank, cards :: [Card }
> > 
> > ...
> > 
> >    | FulHouse { rank, minorRank :: Rank, cards :: [Card] }
> >    | FourOfAKind { rank :: Rank, cards :: [Card] }
> >    | StraightFlush { cards :: [Card] }
> >    | 
> >      deriving Show
> > 
> > instance Eq Hand where  -- if your hands are well-formed, you
> > 
> >    h1 == h2 = cards h1 == cards h2  -- could also derive Eq
> 
> I was thinking of some kind of mixed solution over lunch. This looks
> better than what I had in mind. But what does "well-formed" mean in
> this context?

That the type of hand is properly reflected in the constructor, that the 
hand actually has the quality stated by the constructor and no better,
 for example that a full house is never created as a PairOf or ThreeOfAKind 
(or was it TripleOf?). And that the list of cards is sorted according to 
some criterion (this is also presumed in the explicit Eq instance).

> 
> > quality :: Hand -> Int
> > quality HighCard{} = 0
> > quality PairOf{} = 1
> > ...
> > quality StraightFlush{} = 8
> 
> Could this be replaced by an assoc list of some kind?

Sure, but why? Making it an assoc list would not be trivial, if you don't 
enumerate all possible hands ( ;-), you'd either need a function to create 
a default hand with the same constructor (so you can use the Eq instance to 
do the lookup) or some custom lookup function doing basically the same.

> 
> I was actually contemplating adding a quality field to the record.

If you don't export the constructors and take care to create only hands 
with the correct quality, that is possible. I'm not sure if it gains 
anything, though.

> 
> > instance Ord Hand where
> > 
> >    compare h1 h2 =
> >    
> >      case compare (quality h1) (quality h2) of
> >      
> >        EQ -> case h1 of
> >        
> >                StraightFlush c1 -> compare c1 (cards h2)
> >                FourOfAKind r1 c1 ->
> >                
> >                  case compare r1 (rank h2) of
> >                  
> >                    EQ -> compare c1 (cards h2)
> >                    other -> other
> >                
> >                ...
> >        
> >        other -> other
> 
> What I'd really like to do is collapse the three types of comparison
> (i.e. - hand, rank hand, rank minorrank hand) into one comparison each.

I don't see what you mean, could you elaborate?




More information about the Beginners mailing list