Не удалось сопоставить ожидаемый тип `Bool’ с фактическим типом `Card -> Bool’

#haskell

#haskell

Вопрос:

Вот мой код:

 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) amp;amp; getNumber(x) > getNumber(y) then True else False
  

Сообщение об ошибке:

 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 `(amp;amp;)', namely `sameSuit (x y)'
In the expression: sameSuit (x y) amp;amp; getNumber (x) > getNumber (y)
  

Я не понимаю, почему я не могу вызвать функцию «sameSuit» в finction «beats». Если я вызываю его из prelude, например prelude> sameSuit (Card Club 10) (Карточный клубный туз), он возвращает правильное значение, а тип функции — Bool, а не «Card -> Bool». Что я делаю не так? Кто-нибудь может мне это объяснить?

Комментарии:

1. В качестве отступления: if blahblahblah then True else False можно (и должно) сократить до blahblahblah .

2. Вы можете написать sameSuit намного проще: sameSuit (Card x _) (Card y _) = x == y .

3. Если вы измените порядок конструкторов в CVal и производную Ord вам не нужна getNumber функция в beats , вы могли бы просто использовать x > y .

Ответ №1:

В beats вы, похоже, пытаетесь вызвать несколько функций как function(args) , используя C-подобный синтаксис. Haskell не использует этот синтаксис; функциональное приложение написано с использованием простой смежности токенов, с круглыми скобками, необходимыми только для вложенных выражений.

getNumber(x) безвредно, но бессмысленно. Это анализируется как применение функции getNumber к выражению, заключенному в скобки (x) , что, конечно, эквивалентно just getNumber x , поэтому оно делает то, что вы хотите.

sameSuit (x y) анализируется как применение функции sameSuit к единственному аргументу, выражению в скобках (x y) . Подвыражение, в свою очередь, является применением функции x к y , что не имеет смысла в данном контексте, поскольку x является Card , а не функцией. Вам нужно указать два аргумента для sameSuit , как в sameSuit x y .

Поскольку sameSuit имеет тип Card -> Card -> Bool , sameSuit предоставляется только один аргумент типа Card -> Bool . Об этой ошибке сообщает вам компилятор; вы, очевидно, не можете amp;amp; использовать функцию и Bool .

Если бы компилятор проверял вещи в другом порядке, он также сообщил бы вам, что это x y не тип Card , и это x не функция.

Ответ №2:

Исправленная реализация beats является:

 beats x y = (sameSuit x y) amp;amp; (getNumber x > getNumber y)
  

Итак, вы можете вызвать sameSuit in beats , но вы должны использовать скобки.

Редактировать: На самом деле, вам не нужны скобки. В вашем коде вы вызывали sameSuit (x y) , но вы должны вызывать его без скобок: sameSuit x y

Комментарии:

1. Никогда, никогда не записывайте if c then True else False , if это полностью избыточно. Запись c .