Function Composition
Tags: functional, ios, swift, programming
Published: 2023-02-09 22:52:18


Continuing from our last session on [Side-effect](https://medium.com/techtron/fp-core-concepts-pure-functions-side-effects-270dcdaf473f) we will continue our journey to explore the core concepts of functional programming. The next stop in our journey is at **Composition**. One of the most important concepts of programming for any kind of programming style.

Today we answer 3 basic questions regarding **Composition**. 
 1. What is composition? 
 2. Why is composition required? 
 3. How to compose a function?

### What is Composition?

**Composition** is the process of combining two or more smaller **components** to produce a new larger **component**. The word **component** has different meaning in different **context**. In **functional programming,** **components** are **functions**. These functions compose to new function. 
Put simply, a composition of functions `f` and `g` can be defined as `f(g(x))`, which evaluates from the inside out — right to left. In other words, the evaluation order is:
`x`
`g`
`f`

### **Why is composition required?**

The answer to the above question starts by asking **How do we solve problems?** 
We decompose bigger problems into smaller problems. If the smaller problems are still too big, we decompose them further, and so on. Finally, we write code that solves all the small problems. And then comes the concept of composition, we compose those pieces of code to create solutions to larger problems.

I will argue strongly that composition is the essence of programming. 
We’ve been composing things forever, long before some great engineer came up with the idea of a subroutine. 
Some time ago the **principles of structural programming** revolutionized programming because they made **blocks of code composable**. 
Then came **object oriented programming**, which is all about **composing objects**. 
**Functional programming** is not only about **composing functions and algebraic data structures — it makes concurrency composable** — something that’s virtually impossible with other programming paradigms.

Why do we do what we do? This process of hierarchical decomposition and composition is not imposed on us by computers.

Lets understand this by taking an example. I will present before you 2 pieces of code we need to check which piece of code we can understand better, faster and easily.

    **Code 1:**
    let gradientView = GradientView()
     gradientView.fromColor = UIColor(red: 0.5, green: 0.85, blue: 1, alpha: 0.85)
     gradientView.toColor = .white
     gradientView.translatesAutoresizingMaskIntoConstraints = false

    let logoImageView = UIImageView(image: UIImage(named: “logo”))
     logoImageView.widthAnchor.constraint(equalTo: logoImageView.heightAnchor, multiplier: logoImageView.frame.width / logoImageView.frame.height).isActive = true

    let gitHubButton = UIButton(type: .system)
     gitHubButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
     gitHubButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
     gitHubButton.clipsToBounds = true
     gitHubButton.layer.cornerRadius = 6
     gitHubButton.backgroundColor = .black
     gitHubButton.tintColor = .white
     gitHubButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16)
     gitHubButton.setImage(UIImage(named: “github”), for: .normal)
     gitHubButton.setTitle(“Sign in with GitHub”, for: .normal)

    let orLabel = UILabel()
     orLabel.font = .systemFont(ofSize: 14, weight: .medium)
     orLabel.textAlignment = .center
     orLabel.textColor = UIColor(white: 0.625, alpha: 1)
     orLabel.text = “or”

    let emailField = UITextField()
     emailField.clipsToBounds = true
     emailField.layer.cornerRadius = 6
     emailField.layer.borderColor = UIColor(white: 0.75, alpha: 1).cgColor
     emailField.layer.borderWidth = 1
     emailField.borderStyle = .roundedRect
     emailField.heightAnchor.constraint(equalToConstant: 44).isActive = true
     emailField.keyboardType = .emailAddress
     emailField.placeholder = “blob@gmail.com”

    let passwordField = UITextField()
     passwordField.clipsToBounds = true
     passwordField.layer.cornerRadius = 6
     passwordField.layer.borderColor = UIColor(white: 0.75, alpha: 1).cgColor
     passwordField.layer.borderWidth = 1
     passwordField.borderStyle = .roundedRect
     passwordField.heightAnchor.constraint(equalToConstant: 44).isActive = true
     passwordField.isSecureTextEntry = true
     passwordField.placeholder = “••••••••••••••••”

    let signInButton = UIButton(type: .system)
     signInButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
     signInButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
     signInButton.clipsToBounds = true
     signInButton.layer.cornerRadius = 6
     signInButton.layer.borderColor = UIColor.black.cgColor
     signInButton.layer.borderWidth = 2
     signInButton.setTitleColor(.black, for: .normal)
     signInButton.setTitle(“Sign in”, for: .normal)

    **Code 2:**
    let gradientView = GradientView()
     gradientStyle(gradientView)

    let logoImageView = UIImageView(image: UIImage(named: “logo”))
     implicitAspectRatioStyle(logoImageView)

    baseButtonStyle(.appearance())

    let gitHubButton = UIButton(type: .system)
     gitHubButton.setTitle(“Sign in with GitHub”, for: .normal)
     gitHubButtonStyle(gitHubButton)

    let orLabel = UILabel()
     orLabelStyle(orLabel)
     orLabel.text = “or”

    let emailField = UITextField()
     emailTextFieldStyle(emailField)

    let passwordField = UITextField()
     passwordTextFieldStyle(passwordField)

    let signInButton = UIButton(type: .system)
     signInButton.setTitle(“Sign in”, for: .normal)
     borderButtonStyle(signInButton)

The above **Code1** and **Code2** are creating a piece of UI via code. **Code1** has written code in a very imperative style with each steps exactly defining how to apply style. This makes the code look complicated and harder to understand for a fresh piece of eyes. On the other hand **Code2** uses some pre-built functions to apply style. This makes code more readable, reusable, easy to understand.

The above example reflects the limitations of the human mind. Our brains can only deal with a small number of concepts at a time. One of the most cited papers in psychology, [The Magical Number Seven, Plus or Minus Two](http://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_ Minus_Two), postulated that we can only keep **7 ± 2 **“**chunks**” of information in our minds. The details of our understanding of the human short-term memory might be changing, but we know for sure that it’s limited. The bottom line is that we are unable to deal with the soup of objects or the spaghetti of code. We need structure not because well-structured programs are pleasant to look at, but because otherwise our brains can’t process them efficiently. We often describe some piece of code as elegant or beautiful, but what we really mean is that it’s easy to process by our limited human minds. Elegant code creates chunks that are just the right size and come in just the right number for our mental digestive system to assimilate them.

With this we can surely say that composition is one the key concepts of modern day programming.

### How to compose?

To understand function composition concept we will start with a very trivial example.

Let’s define a function. We can define an increment function that takes an Int and returns an Int:

    func incr(_ x: Int) -> Int {
     return x + 1
    }

To call our function, we pass a value to it.

    incr(2) // 3

Now let’s define a square function to square an integer:

    func square(_ x: Int) -> Int {
     return x * x
    }

We can call it in a similar fashion:

    square(2) // 4

We can even nest our function calls. In order to first increment, then square a value:

    square(incr(2)) // 9

We can also write the above functions as an extension on Int type as follows:-

    extension Int {
     func incr() -> Int {
     return self + 1
     }

    func square() -> Int {
     return self * self
     }
    }

To use our incr method, we can call it directly:

    2.incr() // 3

And we can square the result by chaining our method calls:

    
    2.incr().square() // 9

This is more readable than the earlier version of implementation. The above example reads nicely from left-to-right whereas free functions read from inside-out, and it takes more mental work to see that we call incr before we call square. We can imagine that a more complicated nest of function calls would be all the more difficult to unpack.

### Composition Operators

**Operator |> **
There are many programming languages that uses free functions and but retain this kind of readability by using an infix operator for function application. Using Swift Language we can define an infix operator so that we can compose free functions.
Here we’re defining a “pipe-forward” operator. It’s based on prior art: F#, Elixir, and Elm all use this operator for function application.

    precedencegroup ForwardApplication {
     associativity: left
    }

    infix operator |>: ForwardApplication

    func |> <A, B>(a: A, f: (A) -> B) -> B {
     return f(a)
    }

It’s generic over two types: A and B. The lefthand side is our value, of type A, while the righthand side is a function from A to B. We finally return B by applying our value to our function.
Now we can also define the above example as follows:-

    2 |> incr |> square // 9

This looks a lot like our earlier method version:

    2.incr().square() // 9

The pipe operator is used to apply the left side value to the right side function. Using this we cannot create a new function. It can only be used to apply a left value to right. Hence doing ***incr |> square*** is not going to produce a new function.

Now keeping that in mind lets create a new function with a cool operator which can help us to compose new function from combing 2 smaller functions.

**Operator >>> **
This operator is another standard operator used in many languages like Haskell to compose 2 functions into 1 new function. 
Lets see its implementation:-

    precedencegroup ForwardComposition {
     associativity: left
     higherThan: ForwardApplication
    }

    infix operator >>>: ForwardComposition

    func >>> <A, B, C>(f: [@escaping](http://twitter.com/escaping) (A) -> B, g: [@escaping](http://twitter.com/escaping) (B) -> C) -> ((A) -> C) {
     return { a in
     g(f(a))
     }
    }

It’s a function that’s generic over three generic parameters: A, B, and C. It takes two functions, one from A to B, and one from B to C, and glues them together by returning a new function that passes the value in A to the function that takes A, and passing the result, B, to the function that takes B.

Now we can take our incr function and forward-compose it into our square function:

    incr >>> square

With this we have a whole new function **(Int) -> Int**. This function first increment the value then squares it.

We can use this new function in combination with the above pipe operator to apply a value as follows:-

    2 |> incr >>> square

This is similar to ***2.incr().square() // 9*** but has an added advantage of having a new composed function ***incr >>> square*** and making more readable with the new **pipe operator |>**.

With these two new operators we now have the ability to compose two functions into a new function and the apply a value to it using a pipe operator.

Lets now see few advantages that we have gained following the above approach of composing functions.

### Advantages of Composition

How can we compose these functions in traditional way. If we want to combine **incr** and **square** functionality we have no choice but to extend Int and write another function that compose these 2 functionality.

    extension Int {
        func incrAndSquare() -> Int {
            return self.incr().square()
        }
    }

In use, we can call the new method on a value:

    2.incrAndSquare() // 9

This works but there is lot of boiler plate and noise to achieve this. Plus if we want to reverse this i.e. first square and then increment we need to write a new function again. **When composition takes this much boilerplate and effort, we have to ask ourselves: is it even worth it?**

Meanwhile, function composition is a bite-sized piece that is wholly intact without any noise:

    incr >>> square
    Or 
    square >>> incr

You can further see the reuse by looking at the smallest valid components. If we delete parts of function composition and application, we still have a valid program.

    2 |> incr >>> square
    // every composed unit still compiles:
    2 |> incr
    2 |> square
    incr >>> square

In Swift initializers are at our disposal for function composition. For example, we can take the above new composed function and combine it with String init to convert the above value to a string type:-

    incr >>> square >>> String.init
    // (Int) -> String 

And we can pipe a value through to produce a string result.

    2 |> incr >>> square >>> String.init // “9”

Meanwhile, in the method world, we can’t chain the result along to our initializer. We need to change the order in which we read things by wrapping the initializer around the methods.

    String(2.incr().square())

We can also use the above function composition with map function of an Array like:-

    [1, 2, 3].map(incr >>> square) // [4, 9, 16]

Now this starts to look cool!!! Our composition has seamlessly integrated with map function also.

### Conclusion

With this we can now start seeing how composition helps us to write better readable, reusable and concise code. This sets the basics of function composition. In our upcoming chapters we will see how to use this concept in real world scenarios. Which will be even cooler!!!
So stay tuned…