Композиция функций, работающая по-другому в позволенном?

Чтобы раздеть последний пункт из списка в GHCi, я могу полностью изменить список, взять хвост и затем полностью изменить его снова. Например,

reverse(tail(reverse([1,2,3,4])))

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

Prelude> reverse . tail. reverse [1,2,3,4]

:2:17:
    Couldn't match expected type `a0 -> [a1]' with actual type `[a2]'
    In the return type of a call of `reverse'
    Probable cause: `reverse' is applied to too many arguments
    In the second argument of `(.)', namely `reverse [1, 2, 3, 4]'
    In the second argument of `(.)', namely
      `tail . reverse [1, 2, 3, 4]'

Я думаю, что это означает, что этому не нравится сочинять перемену [1,2,3,4] , таким образом, я пытался поместить скобки вокруг этого, но это дает мне ту же самую ошибку.

Prelude> reverse . tail. (reverse [1,2,3,4])

:3:18:
    Couldn't match expected type `a0 -> [a1]' with actual type `[a2]'
    In the return type of a call of `reverse'
    Probable cause: `reverse' is applied to too many arguments
    In the second argument of `(.)', namely `(reverse [1, 2, 3, 4])'
    In the second argument of `(.)', namely
      `tail . (reverse [1, 2, 3, 4])'

Но если я делаю следующий, это работает правильно.

Prelude> let f = reverse . tail . reverse
Prelude> f [1,2,3,4]
[1,2,3]

Что вызывает эту ошибку и почему закрепление, которому позволяют, мешает этому произойти?

1
nl ja de
@zurgl, который я знаю, это было просто примером проблемы, которую я имел;)
добавлено автор Jim Jeffries, источник
Только, чтобы упомянуть, init функция делают работу.
добавлено автор zurgl, источник

2 ответы

Когда вы видите тип . вы заметите, что он ожидает, что оба из его операндов будут функциями (подходящих типов так, чтобы они могли быть составлены),

Prelude> :i (.)
(.) :: (b -> c) -> (a -> b) -> a -> c   -- Defined in `GHC.Base'
infixr 9 .

Теперь у применения функции есть более высокое предшествование, чем какой-либо инфиксный оператор так

Prelude> reverse . tail . reverse [1,2,3,4]

становится

Prelude> reverse . tail . (reverse [1,2,3,4])

у которого есть неправильный тип, когда вы пытаетесь применить состав. Для состава, чтобы быть правильными необходимо явно дать составу более высокое предшествование, чем применение функции, которое можно сделать, обеспечив явные круглые скобки.

Prelude> (reverse . tail . reverse) [1,2,3,4]

This solutions works but haskellers hate using parentheses. Here comes another operator $ which can save you in such places and make your code more readable than using parentheses. When you see the type of $

Prelude> :i ($)
($) :: (a -> b) -> a -> b       -- Defined in `GHC.Base'
infixr 0 $

Можно ясно видеть, что его precendence (0) является меньше, чем тот из состава (9), который дает вам просто эффект, который вы хотите. Можно просто понизить предшествование последнего применения функции или заменить композицию функций $ .

Prelude> reverse . tail . reverse $ [1,2,3,4]
Prelude> reverse . tail $ reverse [1,2,3,4]
Prelude> reverse $ tail $ reverse [1,2,3,4]

Это прекрасно подходит как первый операнд , $ является функцией, и другой просто ценность правильного типа.

8
добавлено

В позволяют окружают функции, составлены с . и затем список дан как аргумент результату композиции функций:

(reverse . tail . reverse) [1,2,3,4]

В другом случае список дан как аргумент, чтобы перемену , и результат этого пробуют, чтобы быть составленным с некоторыми другими функциями:

reverse . tail . (reverse [1,2,3,4])

Начиная с обратного списка, возвращенного , перемена [1,2,3,4] не является функцией, используя его в качестве аргумента в пользу . приводит к ошибке типа.

4
добавлено
Haskell
Haskell
910 участник(ов)

https://combot.org/chat/-1001043143583 Ссылки на полезные ресурсы: https://ruhaskell.org/links.html ;