Site icon Hari Vignesh

Functional Programming in Kotlin - f(3)

Function Composition

This is the third part of the functional programming series. If you have missed the previous one, start here.

Series pit stops

In this pit stop, we’ll briefly examine how to compose functions.

Pre-requisites

Mathematical Composition

In our first pit stop, we understood how to compose two function or sets mathematically. To brush up quickly, I’m including a small gist here again. If you are confident, please move to next section (Kotlin Composition).

Functions are like legos, meaning — you can use them to build or compose other functions. In other words, function composition is an operation on functions to produce a new function.

For example,

The composition of a function f over g is usually denoted as f o g. This is pronounced as f of g or f round g or can be denoted as f(g(x)). Which gives us,

h(x) = f o g = f(g(x) = f(2x) = (2x) + 1 => 2x + 1
Kotlin

The value of g(x) is substituted in place of x in f(x) ☝️

Hence, f o g = 2x + 1

Fun fact: You can also compose g o f, but f o g and g o f are not equal operations. they may result in the same sometimes though. If we compose g round f for the above functions,

g o f = g(f(x)) = 2(x+ 1) = 2x + 2
Kotlin

Hence, for the mentioned f(x) and g(x)f o g != g o f

Kotlin Composition

Let’s try to compose the same functions in Kotlin

fun f(x: Int) = x + 1 

fun g(x: Int) = 2 * x 

println(f(g(2)) // output -> 5
Kotlin

If you think that’s how the function composition is done using functions, then you are wrong

A function composition is like a binary operation on functions, just like adding integers or numbers, composition is also an operation on functions.

fun f(x: Int) = x + 1 

fun g(x: Int) = 2 * x 

// function composition 

fun compose(f: (Int) -> Int, g: (Int) -> Int): (Int) -> Int = { x -> f(g(x)) }
Kotlin

The compose function, takes in two functions as parameter where each of them have an integer as a parameter and as a return value and it also returns a function of integer as a parameter and as a return value.

We now use the compose function to compose f and g

val fog = compose(::f, ::g) println(fog(2)) // output -> 5
Kotlin

Fun fact: Functions in Kotlin supports functional references (::). We use this operator to access the reference of a function. Just like how we pass value by reference. If the function is of value type or property, then reference is not needed.

Polymorphic function composition

The compose function that we created is restricted to one type. What if we need to compose a function of generic type?

fun r1(x: Boolean): Int = if(x) 1 else 0
fun r2(x: Int): Boolean = if(x == 0) false else true

fun <T, U, V>compose(f: (U) -> V, g: (T) -> U): (T) -> V = 
{ f(g(it)) }

val r1of2 = compose<Int, Boolean, Int>(::r1, ::r2)

println(r1of2(2)) // output -> 1
Kotlin

It might be bit overwhelming to see the generic composition. You are not alone. Take a moment to write such compositions with different types to understand better.

Advantages

TLDR;

Additional References


If you think you have learned something new or if you like this series or you want to boost my morale to publish the next pit stop fast, please share the post. Thanks a lot for reading this article. Stay tuned!!

Exit mobile version