Haskell function composition (forward pipe) - why does this work?
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.
精彩评论