Почему эта функция Haskell относится к этому типу?

Я новичок в Haskell и работаю над упражнением в главе 2 Real World Haskell, где вы пишете функцию, возвращающую предпоследний элемент списка.

Я написал следующую функцию, чтобы попытаться решить эту проблему:

-- file: \Learn Haskell\lastButOne.hs
lastButOne xs = if length xs == 2
                then head xs
                else lastButOne tail xs

Я не понимаю, что компилятор выдает ошибку:

lastButOne.hs:2:1: error:
    • Couldn't match type ‘[a] -> [a]’ with ‘[t]’
      Expected type: ([a] -> [a]) -> [t] -> t
        Actual type: [t] -> t
    • Relevant bindings include
        lastButOne :: ([a] -> [a]) -> [t] -> t (bound at lastButOne.hs:2:1)

Насколько я понимаю, ghci считает, что моя функция должна иметь другой тип, чем он есть, но я не понимаю, почему это происходит и как я могу это исправить.

Изменить: Спасибо за ответы! Я обновил свой код:

-- file: \Learn Haskell\lastButOne.hs
lastButOne xs = if length xs == 2
                then head xs
                else if length xs < 2
                     then error "This list does not have a second-to-last element."
                     else lastButOne (tail xs)

Это устраняет ошибку, когда tail xs интерпретируется как два аргумента, а не как одно выражение. Я также добавил код, который гарантирует, что список не будет слишком коротким. Решение Виллема Ван Онсема лучше, но в качестве упражнения я подумал, что придумал решение, которое использует только концепции, представленные до сих пор в книге.


person AstroEngiSci    schedule 06.07.2017    source источник
comment
lastButOne tail xs равно (lastButOne tail) xs, а не lastButOne (tail xs)   -  person amalloy    schedule 06.07.2017
comment
Вам следует по возможности избегать head, tail. Они не являются идиоматическим Haskell, поскольку 1) они могут привести к сбою вашей программы, если вы когда-либо будете использовать их в пустом списке, и 2) сопоставление с образцом проще в использовании и к тому же более удобно.   -  person chi    schedule 06.07.2017


Ответы (1)


Проблема в строке:

        else lastButOne tail xs

Должен быть:

        else lastButOne (tail xs)

В противном случае ghci вещи, которые вы даете lastButOne двумя аргументами: tail и xs.

Однако вы можете сделать код более элегантным:

lastButOne [x,_] = x
lastButOne xs = lastButOne $ tail xs

Кроме того, вам нужно будет найти способ разрешить списки с одним элементом и пустым списком. Прямо сейчас функция начнет зацикливаться. Идея может заключаться в том, чтобы внести ошибку в эти списки, например:

lastButOne [x,_] = x
lastButOne (_:xs) = lastButOne xs
lastButOne [] = error "The list has no last but one element."
person Willem Van Onsem    schedule 06.07.2017