Dave
Dave

Reputation: 83

Determining if a card is a certain suit

data Card = Card CardValue Suit deriving (Eq)

If I'm given a Card I want to determine which Suit this card is

I have tried using guards, but I'm still unsure on how to use them correctly. If I were to write pseudocode of the kind of thing I'm trying to do it would be along the lines of

if s == D
   then D
else if s == D
   then D

This is how much I've done, like I said I tried to use guards, but I got an error "parse error on input '|' when I used the following code

suitOf :: Card -> Suit
suitOf (Card _ s) = s
   | s == D = D
   | s == S = S
   | otherwise = error "Invalid"

What is it that I'm doing wrong? The logic is fairly simple, I'm just not familiar with the syntax of haskell yet

Upvotes: 1

Views: 78

Answers (3)

chepner
chepner

Reputation: 532448

I'm not sure why there would be an invalid case, but for only three possibilities, I would just write separate equations for each.

suitOf :: Card -> Suit
suitOf (Card _ D) = D
suitOf (Card _ S) = S
suitOf (Card _ _) = error "Invalid"

Without the error case, it is of course just

suitOf :: Card -> Suit
suitOf (Card _ s) = s

and with record syntax you don't even need to define the function yourself:

data Card = Card { rankOf :: CardValue, suitOf :: Suit } deriving (Eq)

Upvotes: 3

paul
paul

Reputation: 1705

You're looking for the case expression (sometimes called match in other languages):

data Suit = Diamond | Spade | Club | Heart deriving (Eq, Ord)
data Card = Card CardValue Suit deriving (Eq)

suitOf :: Card -> Suit
suitOf (Card _ s) =
  case s of
    Diamond -> Diamond
    Spade -> Spade
    _ -> error "Invalid"

where the _ pattern matches all non-matched input -- IIRC case expressions require all patterns to be matched or it'll error, but check me on that.

Note that this works with string literals as the case match patterns too:

toSuit :: String -> Suit
toSuit s =
  case s of
    "Diamond" -> Diamond
    "Spade" -> Spade
    _ -> error "Invalid"

Of course if you weren't going to test for just those two cases you'd merely return the suit directly:

suitOf :: Card -> Suit
suitOf (Card _ s) = s

:)

Reference

Upvotes: 4

Reed Oei
Reed Oei

Reputation: 1528

The problem is that you wrote

suitOf (Card _ s) = s

You don't write the equals sign on the first line of the function, only after each guard. If you change that line to

suitOf (Card _ s)

it should work. Additionally, this will only work if Suit is a type synonym for [Char] (which I assume it is, but just something to check).

Upvotes: 3

Related Questions