1
votes

There is my code:

data Suit = Spade | Heart | Diamond | Club deriving (Eq, Show)
data CVal = Ace | King | Queen | Jack | Ten | Nine | Eight | Seven | Six | Five | Four | Three | Two deriving Show
data Card = Card Suit CVal deriving Show

sameSuit :: Card -> Card -> Bool
sameSuit (Card Spade _) (Card Spade _)     = True
sameSuit (Card Heart _) (Card Heart _)     = True
sameSuit (Card Diamond _) (Card Diamond _) = True
sameSuit (Card Club _) (Card Club _)       = True
sameSuit (Card x _) (Card y _)             = False

getNumber :: Card -> Int
getNumber (Card _ Two)   = 2
getNumber (Card _ Three) = 3
getNumber (Card _ Four)  = 4
getNumber (Card _ Five)  = 5
getNumber (Card _ Six)   = 6
getNumber (Card _ Seven) = 7
getNumber (Card _ Eight) = 8
getNumber (Card _ Nine)  = 9
getNumber (Card _ Ten)   = 10
getNumber (Card _ Jack)  = 11
getNumber (Card _ Queen) = 12
getNumber (Card _ King)  = 13
getNumber (Card _ Ace)   = 14

beats :: Card -> Card -> Bool
beats x y = if sameSuit (x y) && getNumber(x) > getNumber(y) then True else False

Error message:

Couldn't match expected type `Bool' with actual type `Card -> Bool'
In the return type of a call of `sameSuit'
In the first argument of `(&&)', namely `sameSuit (x y)'
In the expression: sameSuit (x y) && getNumber (x) > getNumber (y)

I don't understand why i can't call function "sameSuit" in finction "beats". If I call it from prelude, like prelude > sameSuit (Card Club 10) (Card Club Ace) it returns right value and function type is Bool, not "Card -> Bool". What i do wrong? Can someone explain it to me?

2
As an aside: if blahblahblah then True else False can (and should) be shortened to blahblahblah.dave4420
You can write sameSuit much simpler: sameSuit (Card x _) (Card y _) = x == y.augustss
If you reverse the order of the constructors in CVal and derive Ord you don't need the getNumber function in beats, you could just use x > y.augustss

2 Answers

3
votes

In beats you appear to be trying to call several functions as function(args), using C-like syntax. Haskell does not use this syntax; function application is written by simple token adjacency, with parentheses only needed for nested expressions.

getNumber(x) is harmless, but pointless. It is parsed as the application of a function getNumber to a parenthesised expression (x), which is of course equivalent to just getNumber x, so it does what you want.

sameSuit (x y) is parsed as the application of a function sameSuit to a single argument, the parenthesised expression (x y). The sub-expression is in turn the application of a function x to y, which makes no sense in this context as x is a Card, not a function. You need to supply two arguments for sameSuit, as in sameSuit x y.

Since sameSuit is of type Card -> Card -> Bool, sameSuit supplied with only a single argument is of type Card -> Bool. This is the error the compiler is reporting to you; you obviously can't && a function and a Bool.

If the compiler checked things in a different order it would also tell you that x y is not of type Card, and that x is not a function.

1
votes

A corrected implementation of beats is:

beats x y = (sameSuit x y) && (getNumber x > getNumber y)

So, you can call sameSuit in beats, but you have to use parens.

Edit: Actually, you don't need the parens. In your code you were calling sameSuit (x y), but you have to call it without parens: sameSuit x y