Ответ 1
Функциональное приложение (например, filter even
) связывается более жестко, чем любые операторы, поэтому ваш код эквивалентен:
(take 34 fibseq) |> (filter even) |> (filter (< 4000000)) |> sum
В приведенном ниже коде fibseq
представляет последовательность чисел из последовательности Фибоначчи.
(из кода для решения Project Euler # 2)
Я определил инфиксную функцию |>
:
(|>) x y = y x.
Это позволяет мне сделать следующее (например, unix-конвейер):
take 34 fibseq |> filter even |> filter (< 4000000) |> sum
Мой вопрос: зачем это работает?
Я бы подумал, что take 34 fibseq |> filter even
должен преобразоваться в filter (take 34 fibseq) even
, который (я думаю) приведет к ошибке типа.
Вместо этого он превращается в filter even (take 34 fibseq)
, который работает и что я хочу, но я не понимаю, почему он работает.
Функциональное приложение (например, filter even
) связывается более жестко, чем любые операторы, поэтому ваш код эквивалентен:
(take 34 fibseq) |> (filter even) |> (filter (< 4000000)) |> sum
Это работает из-за приоритета оператора. Оператор приложения функции, сопоставление или (пространство) имеет наивысший приоритет, поэтому
take 34 fibseq |> filter even
анализирует как ((take 34) fibseq) |> (filter even)
, что эквивалентно (filter even) ((take 34) fibseq)
; поскольку приложение функции лево-ассоциативно, это эквивалентно filter even (take 34 fibseq)
.
В общем, любому двоичному оператору может быть присвоен приоритет с объявлением фиксации, например
infixl 0 |>
infixr 9 .
l
или r
указывает, является ли операция левой или правой ассоциативной (т.е. группы a • b • c
как (a • b) • c
или a • (b • c)
); число - целое число от 0 до 9 - задает уровень приоритета. Более высокие числа означают более высокий приоритет (с применением, имеющим эффективный приоритет ∞); например, *
и /
имеют приоритет 7, а +
и -
имеют приоритет 6. Чтобы проверить приоритет оператора в ghci, просто введите :info $
(или какой бы оператор) в приглашении.
И так же, как примечание: ваш код будет работать, но это не так, как я обычно пишу его. Если вам интересно, в Haskell я бы написал этот код с оператором $
, который просто выполняет функциональное приложение, но имеет низкий приоритет: filter even $ take 34 fibseq
. Если бы у меня было больше функций для применения, я бы использовал оператор композиции: fun1 arg1 . fun2 . fun3 arg2 arg3 . filter even $ take 34 fibseq
. Он читает другой путь, но это то, что вы обычно находите в Haskell.