Почему я получаю эту ошибку при попытке сопоставления в списке списков?

#haskell

#хаскелл #haskell

Вопрос:

Я пытаюсь использовать map для написания функции, которая принимает последние элементы списка списков. Например:

  [ [0,0,4],[2,4,2],[1,3,5],[3,1,1] ] => [4,2,5,1]
  

Я написал это:

  func l = map (last l) 
  

и получил эту ошибку:

     > ERROR - Type error in application
 Expression     : func [[0,0,4],[2,4,2],[1,3,5],[3,1,1]]
 Term           : [[0,0,4],[2,4,2],[1,3,5],[3,1,1]]
 Type           : [[c]]
 Does not match : [a -> b]
  

Каков правильный способ сделать это?

Ответ №1:

Вы делаете неправильную вещь с last . То, что вы пытаетесь сделать, это применить это к каждому внутреннему списку внутри внешнего списка l . На самом деле вы применяете это к l самому внешнему списку, и тогда map это не имеет смысла.

Вместо этого вам нужно написать map last l .

Вы можете увидеть правильную форму аргументов для map из его типа:

 map :: (a -> b) -> [a] -> [b]
  

Это означает, что map принимает два аргумента, один типа a -> b и другой типа [a] .

Обратите внимание, что в вашем коде вы указываете только первый аргумент ( last l ). Это допустимая вещь, которую можно сделать в Haskell в целом (посмотрите «частичное применение» или «каррирование»), но здесь первый аргумент должен быть функцией, и last l конечно, это не так.

В этом случае ваш список l имеет тип [a] , поэтому a = [Integer] (игнорируя числовую перегрузку). Первым аргументом должна быть функция типа [Integer] -> b , и вы хотите использовать last , что означает, что b = Integer . Таким образом, конечный результат будет иметь желаемый тип [Integer] .

Ответ №2:

Попробуйте

 func l = map last l
  

нет круглых скобок.

Если вы посмотрите на типы в func [[0,0,4],[2,4,2],[1,3,5],[3,1,1] вызове, вы заметите, что, поскольку l = [[0,0,4],[2,4,2],[1,3,5],[3,1,1]] тип l является [[c]] , то тип last l является [c] , в то время как map ожидает [a -> b] в качестве первого аргумента.

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

1. Он попытался бы сопоставить результат с тем, к чему вы применяете func l , но ошибка типа при попытке передать last l в качестве первого аргумента в map не позволяет ему когда-либо дойти до этой точки.

2. да, это потому, что haskell пытается определить типы из определения функции и конкретного приложения, а они не проверяют.

Ответ №3:

Или даже при использовании обозначения без точек: f = map last

Который в ghci выдает тип:

 GHCI> let f = map last
GHCI> :t f
f :: [[b]] -> [b]
GHCI> f [ [0,0,4],[2,4,2],[1,3,5],[3,1,1] ]
[4,2,5,1]