Skip to main content

Utilities for functions

Functions are an important part of functional programming. Every time we use map or filter we are using functions as arguments, every block is creating a new anonymous function. Arrow brings some patterns which have proven useful in other programming language communities when manipulating functions as values.

Point-free style

The utilities described in this section are part of a particular style of programming called point-free. The name stems from the fact that you never mention explicit arguments, or points, in your code. Some functional programming communities, like Haskell, use this style quite often.

Not idiomatic

Although the following functions are very commonly used in other functional languages, they are not considered idiomatic Kotlin. Most Kotlin developers prefer a block with an explicit call, { dance(2, it) }, instead of manipulating the function value as described in this section, ::dance.partially1(2).

Composition

Composition is used to create a pipeline of functions, in which each of them consume the result of the previous one. In particular, given two functions f(a: A): B and g(b: B): C, the result of g compose f is a new function of type (a: A) -> C which executes f over a, and then g over the result. In graphical form it looks as follows:

Order of composition

When writing a composition pipeline f compose g compose h, remember that computations are applied in right-to-left order; in this case we begin with h and finish with f. This mirrors the way you would write them using explicit invocations, { f(g(h(it))) }.

Partial application

Imagine you have a two-argument function, like this very useful one in a disco,

fun dance(rounds: Int, person: String): Unit { TODO() }

and you want to apply it over a list, where everybody dances the same number of rounds,

fun List<String>.everybodyDancesTwo() = forEach { dance(2, it) }

The block given to forEach is an example of a partially-applied function, that is, an instance in which some arguments of the functions are fixed (in this case the rounds), and others are yet to be given. Instead of an explicit invocation with it, you can use partially1 from Arrow to inject those fixed arguments, as follows.

import arrow.core.partially1

fun List<String>.everybodyDancesTwo() = forEach(::dance.partially1(2))

Arrow provides partiallyN functions up to a reasonable value of N, depending on the amount of values you inject.

Order of partial application

The functions provided by Arrow always start fixing arguments from the left, that is, from the "first" parameter in the signature. At the moment of writing there are no versions of partial application for functions with a receiver.

Currying

Functions in Kotlin take all arguments in one go; writing something like dance(2) is not allowed, hence the need of partial application above. But for every function we can always define a variation which takes arguments one at a time. This process is called currying, and Arrow provides conversion back and forth. The types of the functions make this process quite explicit: we go from (A, B) -> C (two arguments at once) to (A) -> (B) -> C (after giving one argument, we have a function which expects the other one).