views:

135

answers:

4

Hi

I am trying to verify something for myself about operator and function precedence in Haskell. For instance, the following code

list = map foo $ xs

can be rewritten as

list = (map foo) $ (xs)

and will eventually be

list = map foo xs

My question used to be, why the first formulation would not be rewritten as

list = (map foo $) xs

since function precedence is always higher than operator precedence, but I think that I have found the answer: operators are simply not allowed to be arguments of functions (except of course, if you surround them with parentheses). Is this right? If so, I find it odd, that there is no mention of this mechanic/rule in RWH or Learn you a Haskell, or any of the other places that I have searched. So if you know a place, where the rule is stated, please link to it.

-- edit: Thank you for your quick answers. I think my confusion came from thinking that an operator literal would somehow evaluate to something, that could get consumed by a function as an argument. It helped me to remember, that an infix operator can be mechanically translated to a prefix functions. Doing this to the first formulation yields

($) (map foo) (xs)

where there is no doubt that ($) is the consuming function, and since the two formulations are equivalent, then the $ literal in the first formulation cannot be consumed by map.

+2  A: 

Operators can be passed as function arguments if you surround them with parenthesis (i.e. map foo ($) xs, which would indeed be passed as (map foo ($)) xs). However if you do not surround them with parenthesis, you are correct that they cannot be passed as argument (or assigned to variables).

Also note that the syntax (someValue $) (where $ could be any operator) actually means something different: it is equivalent to \x -> someValue $ x, i.e. it partially applies the operator to its left operand (which in case of $ is a noop of course). Likewise ($ x) partially applies the operator to the right operand. So map ($ x) [f, g, h] would evaluate to [f x, g x, h x].

sepp2k
+5  A: 

Firstly, application (whitespace) is the highest precedence "operator".

Secondly, in Haskell, there's really no distinction between operators and functions, other than that operators are infix by default, while functions aren't. You can convert functions to infix with backticks

2 `f` x

and convert operators to prefix with parens:

(+) 2 3

So, you're question is a bit confused.

Now, specific functions and operators will have declared precedence, which you can find in GHCi with ":info":

Prelude> :info ($)
($) :: (a -> b) -> a -> b   -- Defined in GHC.Base

infixr 0 $

class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a

infixl 6 +

Showing both precedence and associativity.

Don Stewart
Thank you. After reading your answer, when you say that my question is a bit confused, I take it to understand that my mention of "function precedence" is wrong, and that functions in themselves do not have any precedence, but rather can be thought of as arguments to the application operator, whitespace. Is this correct? I am still not quite clear on how infix operators fit into this. I have edited my question to reflect how I can best think about it. Is this understanding correct?
Boris
No, not quite. Functions and operators are indistinguishable in Haskell. They can both have different levels of precedence, specified by the user.
Don Stewart
Ok. I'm still trying to figure out the general rule, that leads to list = (map foo) $ (xs) instead of list = (map foo $) xs - which I know is a section. Could it be said, that when deciding, for a given expression, which arguments belong to which functions and operators, functions consume - starting from the left - all the arguments that they can, until they reach an operator. After this, operators consume their arguments, according to their precedence and associativity (This is kind of vague, but I hope you understand). Sorry, if this seems obvious, but it was never really clear to me.
Boris
+5  A: 

The difference is that infix operators get placed between their arguments, so this

list = map foo $ xs

can be rewritten in prefix form as

list = ($) (map foo) xs

which, by the definition of the $ operator, is simply

list = (map foo) xs
Paul Kuliniewicz
Thanks, the mechanical substitution of the infix operator with the prefix function helped me.
Boris
+3  A: 

You are correct. This rule is part of the Haskell syntax defined by the Haskell Report. In particular note in Section 3, Expressions, that the argument to function application (an fexp) must be an aexp. An aexp allows operators as part of sections, and also within a parenthesized expression, but not bare operators.

In map foo $ xs, the Haskell syntax means that this is parsed as two expressions which are applied to the binary operator $. As sepp2k notes, the syntax (map foo $) is a left section and has a different meaning.

I have to confess I've never thought much about this and actually had to look it up in the Report to see why operators have the behavior they do.

John