В ниже кода, fibseq
представляет последовательность чисел от последовательности Fibonacci. (из кода для решения 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)
который работает и является тем, что я хочу, но я не понимаю, почему это работает.
Приложение функции (например, фильтровать даже
) связывает более жестко, чем любые операторы, поэтому ваш код эквивалентен:
(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 (возьмите 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. весело2. fun3 arg2 arg3. фильтровать даже $ take 34 fibseq
. Он читается иначе, но это то, что вы обычно найдете в Haskell.