Q:

How to get simpler but equivalent version of a Haskell expression

Although I have been learning Haskell for some time, there is one common problem I run into constantly. Let's take this expression as an example:
e f $ g . h i . j

One may wonder, given $ and . from Prelude, what are type constraints on e or h for expression to be valid?
Is it possible to get a 'simpler' but equivalent representation? For me, 'simpler' would be one that uses parentheses everywhere and eliminates need to define operator precedence rules.
If not, which Haskell report sections do I need to read to have complete picture?
This might be relevant for many novice Haskell programmers. I know many programmers that add parentheses so that they do not need to memorize (or understand) precedence tables like this one: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

A:

Is it possible to get a 'simpler' but equivalent representation? Of course, this is called parsing, and is done by compilers, interpreters, etc.
90% of the time, all you need to remember is how $ , . and function application f x work together. This is because $ and function application are really simple - they bind the loosest and tightest respectively - they are like addition and the exponent in bodmas.
From your example
e f $ g . h i . j

the function applications bind first, so we have
(e f) $ g . (h i) . j

Function application is left associative so
f g h ==> ((f g) h)

You may have to google currying to understand why the above can be used like foo(a, b) in other languages.
In the next step do everything in the middle - I just use brackets or a table to remember this bit, it's usually straightforward. For example there are several operators like >> and >>= that are used at the same time when you are working with monads. I just add brackets when ghc complains.
So no we have
(e f) $ (g . ((h i) . j))

The order of the brackets doesn't matter as function composition is associative, however Haskell makes it right associative.
So then we have
((e f) (g . ((h i) . j)))

The above (simple) example demonstrates why those operators exist in the first place.

