F# doesn't need parenthesis in functions, or does it?

In a previous posting I mentioned that when you define a function in F# you don't need parenthesis surrounding the parameters, or commas separating them. So, this simple definitions are all valid:

let negate a = -a

 

let add a b = a + b

 

let multiply a b = a * b

When you compile them, you get this messages:

image

negate is a function that takes an integer and returns an integer, add takes two integers and return another, etc.

Now we can type "add 3 4" and we get a 7, but things get interesting if we try to negate the "add 3 4":

image

Why? To solve this mystery we have to understand that function application (i.e. invocation or calling) is an operation as well as +, *, or -. As other operations, application has a precedence (which operation is called first when you've got a mixture) and associativity (if you have "a + b + c", does this mean "(a + b) + c" or "a + (b + c)"). In F# function application has the highest precedence and it is left associative, so that

negate add 3 4

is interpreted as "(negate add) 3 4" and not as "negate (add 3 4)". It pops to the eye that "(negate add)" can't be right, but this is not because you can't pass a function as parameter in F# (which is not only possible but common and pretty useful) but because negate expects an integer as parameter and add is a function, not a number. Maybe the compiler message could be more explicit, but I hope the real source of the problem is more clear now. So, in order for F# to evaluate the expression in the expected order we should write:

negate (add 3 4)

And now, F# first adds 3 and 4, giving 7, and then negates the result giving -7. There are several other scenarios where for getting F# to do the evaluation in the adequate order we must use parenthesis, but remember you will be using them not because invocation requires them but because of precedence and associativity. After this discussion, I think it will be easier to understand the following results:

image

Maybe the only unexpected expression is the last "(-1)", once again the parenthesis are there because "-" is an operator and without them, the expression would be interpreted as "(multiply 3 -) 1", and the compiler will shout because multiply expects two numbers and "-" is a function, not a number. This could be surprising at first (I bumped onto this very same issue with Haskell several years ago) but once you know why, it's not really a problem.

1 Comment

  • Hi,

    You made a mistake at the end of your article. "multiply 3 -1" is parsed as "(multiply 3) - 1". Here, - is a binary operator and "multiply 3" is a function value (cf partial application). This explains the error message.

    Think about it: in "2 - 1" - is also the binary operator. Indeed, this is not parsed as "(2 -) 1".

    If you want to use - as a function, you need extra parenthesis around it : (-). This is very useful when you want to pass it to a function.

    Note : as (-) is a normal function, you could also write: "(-) 3 2".

Comments have been disabled for this content.