Srinivas
Srinivas

Reputation: 2100

parenthesis in Haskell functions

I just want to know how do we know which functions need brackets () and which ones do not? For example

replicate 100 (product (map (*3) (zipWith max [1,2,3,4,5] [4,5,6,7,8])))

works fine. But

replicate 100 (product (map (*3) (zipWith (max [1,2,3,4,5] [4,5,6,7,8]))))

does not work. It is because I put a set of brackets for zipWith. In this small example, zipWith and max do not have brackets, but replicate, product and map do. In general is there a way to know/figure out which functions need brackets and which ones dont.

Upvotes: 3

Views: 7857

Answers (2)

Rodrigo Ribeiro
Rodrigo Ribeiro

Reputation: 3218

Function application is left associative. So, when you write an expression like:

f g h x

it means:

((f g) h) x

And also the type of zipWith provides a clue:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

it says that zipWith has 3 parameters: a function and two lists.

When you write:

zipWith (max [1,2,3,4,5] [4,5,6,7,8])

The interpreter will understand that

max [1,2,3,4,5] [4,5,6,7,8]

will be the first parameter to zipWith, which is type incorrect. Note that zipWith expects a function of two arguments as its first argument and, as pointed out by @Cubic, max [1,2,3,4,5] [4,5,6,7,8] will return the maximum between these two lists according the usual lexicographic order, which will be of type [a], for some type a which is instance of Ord and Num. Said that, the error become evident since you are trying to pass a value of type

(Num a, Ord a) => [a]

where a value of type

(a -> b -> c)

is expected.

Upvotes: 15

Ingo
Ingo

Reputation: 36339

Rodrigo gave the right answer. I'll just add that it is a misconception to think that some functions need parentheses, while others don't.

This is just like in school math:

3 * (4+5)

It is simply not the case that + expressions need parentheses and * expressions don't need them in general.

In Haskell, you can always get away without parentheses at all. Whenever you need to enclose an expression in parentheses, the alternative is to introduce a local name and bind it to that expression, then use the name instead of the expression.

In your example:

replicate 100 (product (map (*3) (zipWith max [1,2,3,4,5] [4,5,6,7,8])))

let list1 = product list2
    list2 = map thrice list3
    thrice x = x*3
    list3 = zipWith max [1,2,3,4,5] [4,5,6,7,8]
in replicate 100 list1

In fact, I often write functions top down thus:

foo x y z = result
  where
   result = ...
   ...

However, as it was said before, expressions that consist of function applications can also often be written without parentheses by making use of (.) and ($) and in such cases, the top down approach from above may be overly verbose and the following would be much clearer (because there is no noise through newly introduced names):

replicate 100
  . product
  . map (*3)
  $ zipWith max [1..5] [4..8]

Upvotes: 5

Related Questions