I think i also got confused the first time i saw that syntax (being used to C-like languages hehe). It started making lots of sense once i got familiar with the concept of currying and functions as first-class values.
Suppose you have a function f with type Int -> Int -> Int (you can read it as "it takes two integers and returns an integer" or "it takes one integer and returns a function that takes an integer and returns an integer"), then:
f
is the function itself, and it is a usable value.
f 42
is a function of type Int -> Int, and a perfectly valid value too. And
f 42 33
is just and Int.
It's like with each application you take one arrow from the function type; until you get something that's not a function any more :)
It's just new and you're not used to it. There's nothing wrong with finding new and different syntax confusing, as long as you're willing to keep an open mind.
If you use it for a while, you'll get used to it. After a while, I've found it makes the most sense. I think it's better because it reduces the amount of syntactic noise in the code.
It's a simple design decision. Function application is the most important part of the language. So it gets the best syntax: none.
is how you would write your example. In Elm, you could also use the function application operator to avoid writing the parentheses:
f a b <| g x y -- EDIT: flipped the operator around
In Haskell, this would be done with $, which used to exist in Elm as well:
f a b $ g x y
Once you get used to mentally parsing the $ as grouping the rest of the expression together--admittedly, it does take a little while--the last version is probably the most readable. At least that's what I've found.
A lot of modern mathematics also drops the parens, especially in areas related to modern algebra. It really makes the most sense and is less ambiguous, with parens not being overloaded between grouping and application.