tags:

views:

125

answers:

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 |> as (|>) 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.

+9  A: 

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

(take 34 fibseq) |> (filter even) |> (filter (< 4000000)) |> sum
sth
+4  A: 

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.

Antal S-Z