Подтвердить что ты не робот

Состав функции Haskell (форвардная труба) - почему это работает?

В приведенном ниже коде 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), который работает и что я хочу, но я не понимаю, почему он работает.

4b9b3361

Ответ 1

Функциональное приложение (например, filter even) связывается более жестко, чем любые операторы, поэтому ваш код эквивалентен:

(take 34 fibseq) |> (filter even) |> (filter (< 4000000)) |> sum

Ответ 2

Это работает из-за приоритета оператора. Оператор приложения функции, сопоставление или (пространство) имеет наивысший приоритет, поэтому 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.