开发者

Haskell function composition (forward pipe) - why does this work?

开发者 https://www.devze.com 2023-01-08 20:59 出处:网络
In the below code, fibseq represents a sequence of numbers from the Fibonacci sequence. (from code to solve Project Euler #2)

In the below code, fibseq represents a sequence of numbers from the Fibonacci sequence. (from code to solve Project Euler #2)

I have defined an infix function |>:

(|>) x y = y x.
开发者_高级运维

This lets me do the following (like a unix pipeline):

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

My question is, why does this work?

I would have thought that take 34 fibseq |> filter even ought to transform into filter (take 34 fibseq) even, which (I think) would lead to a type error.

Instead it seems to be transforming into filter even (take 34 fibseq) which works and is what I want, but I don't understand why it's working.


Function application (like filter even) binds tighter than any operators, so your code is equivalent to:

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


This works because of operator precedence. The function application operator, juxtaposition or (the space), has the highest precedence, so take 34 fibseq |> filter even parses as ((take 34) fibseq) |> (filter even), which is equivalent to (filter even) ((take 34) fibseq); since function application is left-associative, this is then equivalent to filter even (take 34 fibseq).

In general, any binary operator can be given a precedence with a fixity declaration, such as

infixl 0 |> 
infixr 9 .

The l or r says whether the operation is left- or right-associative (that is, whether a • b • c groups as (a • b) • c or a • (b • c)); the number—an integer between 0 and 9—specifies the precedence level. Higher numbers mean higher precedence (with application having an effective precedence of ∞); for instance, * and / have precedence 7, and + and - have precedence 6. To check the precedence of an operator in ghci, just type :info $ (or whichever operator) at the prompt.

And just as a note: your code will work, but it's not how I would typically write it. If you're curious, in Haskell, I would write that code with the $ operator, which just performs function application but is low precedence: filter even $ take 34 fibseq. If I had more functions to apply, I would use the composition operator: fun1 arg1 . fun2 . fun3 arg2 arg3 . filter even $ take 34 fibseq. It reads the other way, but it's what you typically find in Haskell.

0

精彩评论

暂无评论...
验证码 换一张
取 消