Currying and Partial Application

Currying and partial application are two core concepts in functional programming, both of them performs directly at functions with the propose to change its types. It is used mainly to fit a function in any type of composition.

First of all, is necessary to understand how to show a function type. To do that, will be used a sintax similar to F# sintax, functional languagem of .NET platform.

In F# a function type is defined as: parameter -> returns

Therefore, a function with an int parameter that returns a bool value can be described as: int -> bool

When there are multiples parameters the function type is represented by (different from F#): int, int, int -> bool

Now, we can look at the problem to understand the power of these two features.

Functional programming is based mainly on the function concept.

A programação funcional é baseada principalmente no conceito de funções. By definition, a mathematical function must have only one parameter (domain) and a return (range).

Therefore, this would imply that, all functions written in a functional code should contain only one parameter. It Seens impossible, so, how to do this?

The answer is: Currying.

Understanding Currying

The currying process is defined by: Split multiple N parameters functions in N functions. Where each function will receive only one parameter and returns a new function that will receive another parameter, and so on.

Therefore, a simple Add function described by: int, int -> int

Can be described by: int -> int -> int

After the currying process.

The following sample will creates a step-by-step of the currying process in a simple Add function.

First, the original function as described by:

Func<int, int, int> add = 
    (value, value2) => value + value2;

We can use this function normally, according code:

int result
Func<int, int, int> add = (value, value2) => value + value2;
result = add(2, 3);

//result = 5

When executing the currying process in the add function the return will be a new function of type Func<int, Func<int, int>>, that is, it will be a function that will receive an integer value and return a new function waiting for the second integer value.

When the second function receive the last parameter, it will perform the process proposed by add.

See how to perform the currying with Tango.

Func<int, int, int> add = 
    (value, value2) => value + value2;

Func<int, Func<int, int>> addCurried = Currying.Curry(add);
curriedResult = addCurried(2)(3);
//curriedResult = 5

See how to inform the parameters to addCurried function is a bit different, because it generates a series of functions, where each expects only one parameter.

A Tango also provides the Curry method as an extension methods for Func delegates, so you can also perform the above operation as follows:

Func<int, int, int> add =
(value, value2) => value + value2;

//Func<int, Func<int, int>> addCurried = Currying.Curry(add);
Func<int, Func<int, int>> addCurried = add.Curry();
curriedResult = addCurried(2)(3);
//curriedResult = 5

Understanding Partial Application

A partial application is a little different from Currying, but it also involves the process of changing function type.

Through the partial application it is possible to call a method without informing all the parameters. As a result of this operation, a new function will be returned waiting for all remaining parameters.

Notice the differences between partial apply and curry a function.

It will be uses an Add three values function described by: int, int, int -> int

After apply the Currying process the returned function type can be described by: int -> int -> int -> int

At this point, a partial application works completely different from the Currying process, we could even perform different partial applications in the same function.

By inform only one parameter to the function, the obtained result would be: int, int -> int

By informing two parameters, the obtained result would be: int -> int

Similar to the Currying process, the fundamental operation described by the function is executed only when all the parameters are informed, regardless of the number of intermediate functions generated.

See the following sample, first with Currying:

Func<int, int, int, int> add = 
    (value, value2) => value + value2;

Func<int, Func<int, Func<int, int>>> addCurried = add.Curry();
curriedResult = addCurried(2)(3)(5);
//curriedResult = 10

Partial application with one parameter:

Func<int, int, int, int> add = 
    (value, value2) => value + value2;

Func<int, int, int> addPartialApplied = add.PartialApply(2);
partialAppliedResult = addPartialApplied (3,5);
//partialAppliedResult = 10

Partial application with two parameters:

Func<int, int, int, int> add = 
    (value, value2) => value + value2;

Func<int, int, int> addPartialApplied = add.PartialApply(2,3);
partialAppliedResult = addPartialApplied(5);
//partialAppliedResult = 10

All methods available for partial application and Currying in Tango can used in methods of up to 4 parameters, being able to return any type, including void.

In addition, they can be used as static methods of the Currying andPartialApplication classes or as extensions to Func andAction delegates.

Last updated