Functional Programming – Why Use Space for Function Application?

functional programmingprogramming-languages

Having looked at some languages for functional programming, I always wondered why some fp-languages use one or more whitespace characters for function application (and definition), whereas most (all?) imperative/object-oriented languages are using parentheses, which seems to be the more mathematical way. I also think that the latter style is much more clear and readable than without the parens.

So if we have a function f(x) = x² there are the two alternatives to calling it:

  • FP: f x

    Examples:

    • ML, Ocaml, F#
    • Haskell
    • LISP, Scheme (somehow)
  • Non-FP: f(x)

    Examples:

    • Almost all imperative languages (I know, see the comments/answers)
    • Erlang
    • Scala (also allows "operator notation" for single arguments)

What are the reasons for "leaving out" the parentheses?

Best Answer

which seems to be the more mathematical way

functional languages are inspired by lambda calculus. In this field, parentheses are not used for function application.

I also think that the latter style is much more clear and readable than without the parens.

Readability is in the eye of the beholder. You are not used to reading it. It is a bit like mathematical operators. If you understand the associativity, you only need a few parens to clarify the structure of your expression. Often you don't need them.

Currying is also a good reason to use this convention. In haskell, you can define the following:

add :: Int -> Int -> Int
add x y = x + y

x = add 5 6 -- x == 11
f = add 5
y = f 6 -- y == 11
z = ((add 5) 6) -- explicit parentheses; z == 11

With parens, you could use two convention: f(5, 6) (not curried) or f(5)(6) (curried). The haskell syntax helps to get used to the currying concept. You can still use a non-curried version, but it is more painful to use it with combinators

add' :: (Int, Int) -> Int
add' (x, y) = x + y
u = add'(5, 6) -- just like other languages
l = [1, 2, 3]
l1 = map (add 5) l -- [6, 7, 8]
l2 = map (\x -> add'(5, x)) l -- like other languages

Notice how the second version forces you to register x as a variable, and that the subexpression is a function which takes an integer and adds 5 to it? The curried version is much lighter, but also considered by many as more readable.

Haskell programs makes extensive use of partial application and combinators as a mean of defining and composing abstractions, so this is not a toy example. A good function interface will be one where the order of parameters provides a friendly curried usage.

Another point: a function without parameters should be called with f(). In haskell, since you only manipulate immutable lazy evaluated values, you just write f, and consider it as a value which will need to perform some computations when needed. Since its evaluation won't have any side effect, it makes no sense to have a different notation for the parameterless function and its returned value.

There are also other conventions for function application:

  • Lisp: (f x) -- prefix with external parentheses
  • Forth: x f -- postfix