Why Functional Programming?

The facination of doing programming is to solve the exist problems. Revisit the history of software development, at first place we have procedure-oriented programming. As the system becomes bigger, the codebase is so hard to maintain and adding new features. Then a few genius comes out the idea with OOP with the SOLID principles to guide the daily dev work.

If there is one rule in software development, i think that must be no silver bullet. The OOP has ruled the system development for more that 20 years (The number comes from JAVA becomes popularity). More and more devs find object-oriented programming sucks:

Mutable state of instances, variables

Hard to conform with SOLID when business logic becomes messy

Hard to test caused by improper DI

So many lines of code

Boring …

Now people are thinking how to solve them:

There is no mutable variables

The functionality should be encapsulated

I don’t want exception, the compute unit (AKA function) should be pure

The code should be clean

Easy to test

Parallelism

Make me happy …

That’s what the FP try to implemented. What’s the design principle for FP? Category theory. It’s simple as its name. As the saying goes, there is no silver bullet.

What sucks in FP?

Learning curve

Too young

The world is not perfect

Please add more …

Pure Function

A function can be pure or impure. Usually we use pure function in FP as much as we can. There are a few conditions for pure function:

Give the same input argument to the function, it should always return same output.

The function should only depends on the return value to change the whole “world”, which means no side effects. The side effects can be an exception, mutate an object, IO operation, etc.

With pure function, it’s possible to make sure our program is referential transparency which means that an expression always evaluate to the same result in any piece of code. Referential transparency makes the code easier to reason about.

What can be done if we don’t read any inputs and write any outputs?

Usually, we can refactor impure function to be pure by adding a proper context (here a context is what a value wrapped in.) like Option, cats.effect.IO or monix.eval.Task to the function return type. Some cases are:

Use Either to represent exception

Use IO or Task to delay the I/O operation

Function Composition

Basicly, FP is about fucntion composition. That means:

// A, B, C are types
f: A -> B,
g: B -> C,
g compose f: A -> C

But how should we deal with the values wrapped in context like Option or IO? There could be lots of scheleton code if we still use simple function composition in this case. Then, there comes monad, it opens the context and keeps the context same in the following computation. Usually we use for comprehension to simplise the control flow:

val result = for {
a <- Option.apply(1) // this is equal to Some(1)
b <- Option.apply(2)
} yield a + b
// result is: Some(3)

Monad

Define a Monad

In this section, we will implement an ‘ugly’ Option monad, without considering any variance in type marameter:

Free Monad

Why need it

There is developers want to decomose data from the interpreter, which means there can be multiple interpretation for the same piece of computation. It would be helpful if we want to invoke different computation in different place. In this case, we need to wrap such computation in a context which can be composed with the computation in same context. This is a special monad which is called free. Typically ADT is common used to represent the data.

How to use

In practice, we can view Free as a clever way of forming Monad with providing Functor.

Following steps show the way to use free monad provides by cats library (need to add cats-free dependency):

Usually, we will have a lot of ADTs in the code, but unrelated monad do not compose. Cats has given an option to chain the different ADT by using coproduct type. We are not going to discuss the detail here, but worth to dig it more here if you are interested.

Monad transformer

Why need it

Imagine there is a piece of code to fetch the address of a user by its id:

One thing need to mention is that many monad transformers could be stack unsafe, like StateT .

Extensible Effect

Why need it

Monad transformers has a limited nest layers, also must keep the order same in different computation. What if we have some super way to rule all the monads? In this case we can walk through the control flow without worring the different monad. Finally it will free us from assembling different manads.

The principle ideas to understand effects are:

An effect is most easily understood as an interaction between a sub-expression and a central authority that administers the global resources of a program.

An effect can be viewed as a message to the central authority plus enough information to resume the suspended calculation.

What’s the implementation

The core of Eff library is Eff monad and the open union. Defining effects and their interactions is done by the user. There are some common effects provided by the library like ReaderEffect, IOEffect etc for convenience.