Хаскелл: Почему я не могу использовать last вместо tail в этой небольшой функции?

#haskell

Вопрос:

Если я использую tail в следующей функции (которая предназначена для обмена числами в списке 2 на 2), она компилируется и работает нормально:

     pairExchange :: [a] -> [a]

    pairExchange [] = []
    pairExchange [a] = [a]
    pairExchange (x:xs) | length xs > 2  =  head xs : x : pairExchange (tail xs)
                        | otherwise  =  head xs : x : tail xs
 

но если я использую «последний xs» в последней строке вместо «хвост xs» (что было бы то же самое, так как список будет содержать только 2 элемента), я получу следующую ошибку:
«Происходит проверка: не удается построить бесконечный тип: a ~ [a]»

Я хотел бы знать, почему это так, заранее благодарю вас.

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

1. tail :: [a] -> [a]; last :: [a] -> a . То есть last возвращает элемент, а не список. Но ты привел верный аргумент, чтобы (:) :: a -> [a] -> [a] . Затем вывод типа пытается рассматривать список как список списков и завязывается в узлы.

2. Кое — что, над чем вам может понравиться ломать голову: как вы думаете, что пойдет не так, если вы полностью откажетесь от проверки длины (и otherwise предложения)? Согласен ли GHC с вами? (Эта головоломка не имеет отношения к вашей проблеме.)

Ответ №1:

У них разные типы:

 λ> :t last
last :: [a] -> a
λ> :t tail
tail :: [a] -> [a]
 

Следовательно last xs , имеет тип a и tail xs имеет тип [a].

В этом случае Occurs check: cannot construct the infinite type: a ~ [a] означает, что он нашел a, когда ожидал [a].

Демонстрация:

 λ> :t (:)
(:) :: a -> [a] -> [a]
λ> :{ 
     f :: [a] -> [a] 
     f xs = head xs : last xs -- (1)
   :}
   <interactive>:102:35: error:
     • Occurs check: cannot construct the infinite type: a ~ [a]
   
λ> :{ 
     f :: [a] -> [a] 
     f xs = head xs : [last xs] -- (2)
   :}
λ> f [1,2,3]
[1,3]
 

В (1) last xs имеет тип a. В (2) [last xs] имеет тип [a].