Lazy functions

When currying or partial function evaluation takes place, supplying N actual arguments to a function that expects M arguments where N < M will result in a higher order function with M-N arguments. Technically, when N == M, the function has all the arguments needed to do a full evaluation:

    plus(3, 2)  full evaluation
    plus(?, 6)  partial evaluation
Lazy functions are subsets of partial function evaluation or currying

Now, we shall revisit the concept of lazy functions introduced before in passing. That is, the first function invocation will not really "fully evaluate" the function regardless if all or some of the arguments are supplied. A second function invocation will always be needed to perform the actual evaluation. At the point in the second call, the caller is expected to supply all arguments that are still missing. Still vague? To clarify, a partially evaluated function:

        f(1, ?, ?)

results to an unnamed function unnamed_f(a, b) that expects the two (2) more arguments that are still missing when the first function, f, is invoked. Since unnamed_f(a, b) is already a second level evaluation, all arguments must be supplied when it is called and the result is finally evaluated. Example:

    f(1, ?, ?) ---> unnamed_f(a, b)

then

    unnamed_f(2, 3) ---> evaluate_and_return_value_for f(1, 2, 3)

This function call sequence can be concatenated:

    f(1, ?, ?)(2, 3)

The second level function unnamed_f is not curryable. All of its still missing arguments must be supplied when it is called.

As mentioned, even though we have all the arguments in the first call, the function is not yet evaluated (thus lazy). For example, a function call:

    f(1, 2, 3)

remember that the first function invocation will not really evaluate the function even if all the arguments are fully supplied. Thus:

    f(1, 2, 3) ---> unnamed_f()
Generators

In FP, unnamed_f() is a generator; a function that has no arguments but returns a result. Not to be confused with Phoenix generators to be discussed later.

Then:

    unnamed_f() ---> evaluate_and_return_value_for f(1, 2, 3)

This function call sequence can be concatenated as:

    f(1, 2, 3)()

Lambda (unnamed) functions and currying (partial function evaluation) can also be applied to operators. However, unlike lazy functions, operators are fully evaluated once all the arguments are known and supplied, unless some sort of intervention is applied to coerce the operator expression to be lazily evaluated. We shall see more details on this and how this is done later.