So from our last session, we learned about Function Composition. Why do we need it? How to do it? How to make composition convenient by removing a lot of boilerplate? So continuing with the same theme of functional programming. The next stop will be at Function Currying.
So today we will try to answer following questions regarding Function Currying:-
- What is Function Currying?
- Why do we need function Currying?
- How to convert a function to curried function?
- How Function Currying help us in a day to day programming?
With these questions answered, we will be one step closer to using Function Composition more efficiently in a day to day programming.
So let's start now.
What is Function Currying?
Function Currying is a process of decomposing a function with multiple arguments to a sequence of functions with one argument. Currying helps us to apply value for some arguments and in return a partial function. Let's try to understand the concept with an example.
Let us see a simple Curried Function:-
// Normal way to define a function with 2 Arguments
func set<T>(key: String, data: T)
// Curried Function
func set<T>(key: String)(data: T)
Why do we need function Currying?
We generally use function currying because of following advantages:-
A curried function falls under the category of single argument function.
On applying each value it generates a Partial Function which can be reused at multiple places
Multiple argument functions are very hard to compose. Single argument functions can be composed easily
Since it can be composed easily it gets to use all superpowers of Function Compositions
But there are a few disadvantages too:-
In Swift by default, there are very few curried functions
All Legacy code is not curried mostly
Converting a non-curried to curried function is tedious and with a lot of boilerplate
How to convert a function to curried function?
Let’s take the above sample of set function with 2 arguments and see how to curry it.
// Simple set function
func set<T>(key: String, data: T) -> Void
// Curried wrapper for set function
func setCurried<T>(key: String)(data: T) -> Void {
return { (key: String) -> (data: T) -> Void in {
(data: T) -> Void in
// call your normal function
set(key: key, data: data)
}
}
}
Generalizing the above implementation for 2 arguments:-
/// Curries a function of two arguments.
///
/// — Parameter function: A function of two arguments.
/// — Returns: A curried function.
public func curry<A, B, C>(_ function: [@escaping](http://twitter.com/escaping) (A, B) -> C)
-> (A)
-> (B)
-> C {
return { (a: A) -> (B) -> C in
{ (b: B) -> C in
function(a, b)
}
}
}
/// Using the above generalisation
/// This yields a new function with following function signature
/// (String) -> (T) -> Void
curry(set)
As we have generalized over 2 arguments similarly we can generalize over N arguments. But due to Swift limitation of generalizing over N arguments is not possible. Hence we have implemented generalization till 12 arguments. This would cover 99% of the cases. Rarely do we create a function with more than 12 parameters. SwiftCurry
How Function Currying help us in a day to day programming?
Let us say we have created a caching framework with the following function signatures (Normal way to define a function with 2 Arguments):-
func set<T>(data: T, key: String) // Set Cache function definition
Now when we use this function for setting user’s preference for app theme we will do it as follows
set(data: .dark, key: “AppThemeKey”)
The above code looks perfectly fine. But it leaves many places to make errors. Few points are:-
The key is a plain string hence while setting this value at multiple places can lead to mistakes.
Key is not tied to its value. Hence one can make a mistake of saving the same value with a different key
Now let us try to solve the above issues.
// Convert the above set function to curried version
let curriedSet = curry(set)
Let us generate a partial function to set App Theme
let setAppTheme = curriedSet(key: “AppThemeKey”)
/// To use it
setAppTheme(data: .dark)
By creating the above partial function we have ensured that at no place developer needs to explicitly set the key hence solving the issue of making mistake with key String.
Also since we have defined the above partial function with a very particular objective to only set App Theme. Hence reducing the chances of making mistake in setting something else to expect App Theme.
We can make this more strict by introducing compile-time checks for a key-value pair but we will that for sometime later.
For now, I will leave you thinking about Curried & Practical Function. We will see more practical usage later.