-4

I'm a beginner learning Haskell. But not so sure how Either works in pattern matching.

Here is my code:

type Rank = Either Pip Court
type Pip = Int
type Deck = [Card]
data Card = Joker | Card Suit Rank
data Court = Ace | Jack | Queen | King deriving (Show, Eq, Ord)
data Suit = Hearts | Diamonds | Clubs | Spades deriving (Show, Ord, Eq)

snap :: Card -> Card -> String
snap Joker Joker = "SNAP"
snap (Card s1 r1) (Card s2 r2)
    | r1 == r2 = "SNAP"
snap _ _ = "..."

GHCi told me that Couldn't match type ‘Court’ with ‘Either Pip Court’, can anyone help me with it?

  • 4
    Can't reproduce. That code loads fine in GHCi on my system. – Mark Seemann Dec 19 '18 at 09:10
  • 1
    What do you try in GHCi? – assembly.jc Dec 19 '18 at 09:11
  • 3
    what part of the script does GHC complain about?, post the full error – Bargros Dec 19 '18 at 10:38
  • 3
    It sounds like you are trying to create a card with something like `Card Hearts Jack` instead of `Card Hearts (Right Jack)`. (Similarly, `Card Hearts (Left 3)`.) – chepner Dec 19 '18 at 12:31
  • @chepner I think I misunderstood the meaning of either which failed to match the data type, especially when type is so important in such a language:) – Escutche0n Dec 23 '18 at 07:23
  • @assembly.jc I tried the the card type but forgot Left / Right in Either type. :) – Escutche0n Dec 23 '18 at 07:24
  • @Escutche0n Another way to think of it is to remember that every value belongs to exactly one type. `Jack` belongs to `Court`, so it can't belong to `Either Pip Court`, but `Right Jack` can. (This applies to polymorphic values as well; `3` is not a single value, but a general name that can be inferred to be `3::Int, `3::Float`, etc as necessary.) – chepner Dec 23 '18 at 13:54

1 Answers1

1

Either isn't simply a union of types; it's a tagged union, which means every value has to explicitly specify which "side" of the type the wrapped value occurs on. Here's an example, (with a Show instance derived for your Card type):

*Main> Card Hearts Jack

<interactive>:3:13: error:
    • Couldn't match type ‘Court’ with ‘Either Pip Court’
      Expected type: Rank
        Actual type: Court
    • In the second argument of ‘Card’, namely ‘Jack’
      In the expression: Card Hearts Jack
      In an equation for ‘it’: it = Card Hearts Jack

Card expects an argument of type Either Pip Court, but you gave it a plain Court value. With an explicit wrap:

*Main> Card Hearts (Right Jack)
Card Hearts (Right Jack)

The same applies to creating a numbered card:

*Main> Card Hearts 3

<interactive>:5:13: error:
    • No instance for (Num Rank) arising from the literal ‘3’
    • In the second argument of ‘Card’, namely ‘3’
      In the expression: Card Hearts 3
      In an equation for ‘it’: it = Card Hearts 3
*Main> Card Hearts (Left 3)
Card Hearts (Left 3)

You don't need to change the definition of snap, because there is already an Eq instance for Either as long as both wrapped types have Eq instances themselves; it considers any Right value unequal to any Left value, and matching Right or Left values are equal if the wrapped values are equal.

*Main> snap (Card Hearts (Right Jack)) (Card Hearts (Left 3))
"..."
*Main> snap (Card Hearts (Right Jack)) (Card Spades (Right Jack))
"SNAP"
chepner
  • 497,756
  • 71
  • 530
  • 681