user2975699
user2975699

Reputation: 595

Operator priority in haskell

I have a function g1 = flip map . (flip take $ iterate (+1) 1) I am wondering why i can't write

g1 = flip map . $ flip take $ iterate (+1) 1 ? I know that $ has lowest priority but don't understand why we can have $ in flip take $ iterate (+1) 1 but not in g1 after the dot

Upvotes: 1

Views: 680

Answers (2)

michas
michas

Reputation: 26555

Let's take an even easier example:

Prelude> :t id . (id)
id . (id) :: c -> c
Prelude> :t id . $ id

<interactive>:1:6: parse error on input `$'
Prelude> :t (id .) $ id
(id .) $ id :: c -> c

The $ operator has very low priority, hence it is evaluated last and takes a function as a left argument:

Prelude> :i ($)
($) :: (a -> b) -> a -> b       -- Defined in `GHC.Base'
infixr 0 $

Unfortunately without parentheses you get no proper function for those cases:

Prelude> :t id .

<interactive>:1:5:
    parse error (possibly incorrect indentation or mismatched brackets)
Prelude> :t (id .)
(id .) :: (a -> c) -> a -> c
Prelude> :t flip take
flip take :: [a] -> Int -> [a]
Prelude> :t flip map .

<interactive>:1:11:
    parse error (possibly incorrect indentation or mismatched brackets)
Prelude> 

This is the same reason, why you need to write (+) when referring to the plus operator itself:

Prelude> :t +

<interactive>:1:1: parse error on input `+'
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t 1+

<interactive>:1:3:
    parse error (possibly incorrect indentation or mismatched brackets)
Prelude> :t (1+)
(1+) :: Num a => a -> a

Conclusion: You simply cannot have two operators directly side by side.

Upvotes: 0

raymonad
raymonad

Reputation: 949

Note that the second form results in a parse error, not a type error. You simply can't have two operators side by side. When you put an expression between . and $, then operator priorities come into play. Since . has higher priority, the expression between . and $ becomes the right operand of . and the result of the dot operator becomes the left operand of the dollar. If you were to reverse their priorities (or write code assuming they had been), you would get a type error (unless the types happen to match either way).

You can write something like the second form using an operator section:

g1 = (flip map .) $ flip take $ iterate (+1) 1

But I'd say the most readable point-free notation is

g1 = flip map . flip take (iterate (+1) 1)

And actually iterate (+1) 1 can be shortened:

g1 = flip map . flip take [1..]

Next, a little desugaring helps us get rid of the flip take:

g1 = flip map . enumFromTo 1

Upvotes: 3

Related Questions