Не удалось совместить ожидаемый тип `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

Если вы хотите совместить последний элемент, посмотрите на этот ответ - Можете ли вы использовать сопоставление образцов для привязки последнего элемента списка?