Given class X and Y, what's the most idiomatic approach to creating instances of each other's class? e.g. -
instance (X a) => Y a where ...
instance (Y a) => X a where ...
I'd like to avoid extensions. Also, I am aware that this could cause some nasty infinite recursion, so I'm open to a completely different approach to accomplish the same thing and stay relatively DRY. Below gives some context as to the exact problem I am having -
data Dealer = Dealer Hand
data Player = Player Hand Cash
class HasPoints a where
getPoints :: a -> Int
class (HasPoints a) => CardPlayer a where
getHand :: a -> Hand
viewHand :: a -> TurnIsComplete -> Hand
hasBlackjack :: a -> Bool
hasBlackjack player = getPoints player == 21 &&
(length . getCards . getHand) player == 2
busts :: a -> Bool
busts player = getPoints player > 21
I'd like to do this -
instance (CardPlayer a) => HasPoints a where
getPoints = getPoints . getHand
But it seems I must do this -
instance HasPoints Dealer where
getPoints = getPoints . getHand
instance HasPoints Player where
getPoints = getPoints . getHand
EDIT
Seems my favorite approach is to keep the HasPoints
typeclass and implement CardPlayer
as data
instead.
data CardPlayer = Dealer Hand | Player Hand Cash
instance HasPoints CardPlayer where
getPoints = getPoints . getHand
getCash :: CardPlayer -> Maybe Cash
getHand :: CardPlayer -> Hand
viewHand :: CardPlayer -> TurnIsComplete -> Hand
hasBlackjack :: CardPlayer -> Bool
busts :: CardPlayer -> Bool
-- I wanted HasPoints to be polymorphic
-- so it could handle Card, Hand, and CardPlayer
instance HasPoints Hand where
getPoints Hand { getCards = [] } = 0
getPoints hand = if base > 21 && numAces > 0
then maximum $ filter (<=21) possibleScores
else base
where base = sum $ map getPoints $ getCards hand
numAces = length $ filter ((Ace==) . rank) $ getCards hand
possibleScores = map ((base-) . (*10)) [1..numAces]
instance HasPoints Card where
-- You get the point