Не удалось совместить ожидаемый тип `a 'с фактическим типом` [a]'
Я смог выполнить следующий код безупречно
myLast :: [a] -> a
myLast [] = error "Can't call myLast on an empty list!"
myLast (x:_) = x
но я получаю эту ошибку Couldn't match expected type `a' with actual type `[a]'. `a' is a rigid type variable bound by the type signature for myLast :: [a] -> a
для следующего кода:
myLast :: [a] -> a
myLast [] = error "Can't call myLast on an empty list!"
myLast (_:x) = x
Я новичок в Haskell, и сообщение об ошибке слишком греческое и латинское для меня. Из того, что я могу понять, компилятор не может вывести тип во втором случае. Может ли кто-нибудь указать мне на то, что на самом деле происходит здесь?
Ответы
Ответ 1
Вы объявляете входные данные списком типа [a]
, а остальные - типом a
.
Список типа [a]
в Haskell состоит из главы типа a
и tail, списка типа [a]
. Конструктор cons :
принимает в качестве аргументов голову и хвост.
Когда вы деконструируете список как (x:y)
, x
- это голова, а y
- это хвост. Итак, во втором фрагменте кода вы связываете хвост списка, который имеет тип списка [a]
, когда ваша сигнатура типа требует, чтобы вы вернули значение типа a
(глава является одним из примеров).
Ответ 2
Понимание того, что действительно означает :
, поможет расшифровать сообщение об ошибке. :
можно рассматривать как функцию, которая принимает элемент и список и возвращает список, первым элементом которого является первый элемент, а остальная часть - второй аргумент, или:
(:) :: a -> [a] -> [a]
Подойдя к вашей функции, вы написали myLast :: [a] -> a
; однако тип myLast (_:x) = x
равен myLast :: [a] -> [a]
, так как второй аргумент :
(который вы назвали x
) сам по себе является списком.
Кроме того, в общем случае, когда вы не понимаете что-то в Haskell, вы должны сначала просмотреть его тип, используя :t
в GHCI.
Ответ 3
(_:x)
соответствует _ с головой и x с хвостом списка. Тип хвоста списка - [a]. Вы пытаетесь вернуть [a] ', где, поскольку объявление функции указывает тип возвращаемого значения как.
myLast (_:x) = x
Если вы хотите совместить последний элемент, посмотрите на этот ответ - Можете ли вы использовать сопоставление образцов для привязки последнего элемента списка?