A function can return another function.

add' :: Int -> (Int -> Int)
add' x y = x+y

Here, add’ is a function that takes an Int for an argument and results in a function of type: Int -> Int. The function definition takes an integer x, followed by an integer y, it can be curried.

addThree = add' 3  -- This is now a function with type: Int -> Int
result = addThree 5  -- Evaluates to 8

Another example,

mult :: Int -> (Int -> (Int -> Int))
mult x y z = x*y*z

And is applied as following:

mult x y z
-- Means same as:
((mult x) y) z

When used, it is like:

multTwo = mult 2   -- This is now a function with type: Int -> (Int -> Int)
multTwoThree = multTwo 3  -- This is: Int -> Int
result = multTwoThree 4  -- Evaluates to 2 * 3 * 4 = 24

-- or just:

result = mult 2 3 4  -- Also evaluates to 24

Partial application is about using curried functions, applying only some arguments and getting back a new function.

double = mult 2   -- This is now a function with type: Int -> (Int -> Int)

result = double 3 4  -- Evaluates to 2 * 3 * 4 = 24

quadruple = double 2  -- Now quadruple :: Int -> Int
result = quadruple 3  -- Evaluates to 2 * 2 * 3 = 12

The arrow function -> in Haskell types is assumed to associate from the right.

Int -> Int -> Int -> Int

-- is:

Int -> (Int -> (Int -> Int))

So, unless tuples are required, all functions in Haskell with multiple arguments are actually defined as curried functions, with a way to reduce excessive parenthesis.