Композиция функций Haskell (передают канал) - почему это работает?

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

20
задан sth 13 June 2011 в 15:45
поделиться

2 ответа

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

(take 34 fibseq) |> (filter even) |> (filter (< 4000000)) |> sum
24
ответ дан 30 November 2019 в 00:27
поделиться

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

8
ответ дан 30 November 2019 в 00:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: