Pages

Wednesday 17 December 2014

The power of Lambda-Type in Higher kinded types

In the previous posts we have explored the type classes, we have defined the Semigroup type class in this post and then we have exploited the State Monad.

I would like to start this post from the definition we have done on the State Monad:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  trait State[S, A] {
    def apply(s:S): (A, S)
    def map[B](f:A=>B): State[S, B] = State { s =>
        val (a, s2) = this(s)
        (f(a), s2)
    }
    def flatMap[B](f:A=>State[S, B]): State[S, B] = State { s=>
      val (a, s2) = this(s)
      f(a)(s2)
    }
  }
  
  object State {
    def apply[S, A](f: S=>(A, S)) = new State[S, A] {
      def apply(s:S) = f(s)
    } 
  }

Without talking about Category Theory lets understand what make the above trait a Monad.

Monad is essentially a container of other types and it defines some transformation methods between different contained types.
Because this can get quite confusing by using words lets use code to explain it:

1
2
3
4
  trait Monad[M[A], A] {
    def map[B](f: A=>B): M[B]
    def flatMap[B](f: A=>M[B]): M[B]
  }

Quite interesting... Monad is nothing else that a trait which defines map and flatMap across container types (If you want to dig down to the math behind that then Category Theory is what you need to look for).

I would like now to re-define State as a member of Monad, something like: Monad[State[S, A], A] ...

Lets try it:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  trait Monad[M[A], A] {
    def map[B](f: A=>B): M[B]
    def flatMap[B](f: A=>M[B]): M[B]
  }
  
  trait State[S, A] {
    def apply(s:S): (A, S)
  }
  
  object State {
    def apply[S, A](f: S=>(A, S)) = new State[S, A] {
      def apply(s:S) = f(s)
    } 
  }

Ok so now we have moved map and flatMap methods away from State and created a new trait for Monad. We want now State to be a member of Monad so it can inherit map and flatMap.
Ideally we would like to do something like that:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  object Monad {
    implicit def stateMonad[S, A](sm:State[S, A]) = new Monad[State[S, A], A] {
      def map[B](f:A=>B) = State[S, B] { s => 
        val(a, s2) = sm(s)
        (f(a), s2)
      }
      
      def flatMap[B](f: A=>State[S,B]) = State[S, B] { s =>
       val (a, s2) = sm(s)
       f(a)(s2)
      }
    }
  }

The sad part of the above code is that Line 2 will NOT COMPILE!

In fact the Monad trait accept a type M[_] and not M[_ , _] !!!!

Obviously I can go and change the Monad trait definition but then it will not work for container with single type and so on....

We need to do some magic and transform State[S, A] in something with only one type parameter but without loosing in "Generalisation".

That's where we use Lambda-types. Have a look on the below code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  object Monad {
    implicit def stateMonad[S, A](sm:State[S, A]) = new Monad[({type λ[A]=State[S,A]})#λ, A] {
      def map[B](f:A=>B) = State[S, B] { s => 
        val(a, s2) = sm(s)
        (f(a), s2)
      }
      
      def flatMap[B](f: A=>State[S,B]) = State[S, B] { s =>
       val (a, s2) = sm(s)
       f(a)(s2)
      }
    }
  }

I know what you are thinking right now... WTF.... At least that was my first reaction when I have seen Lambda-types for the first time.

What's going on line 2 ?
I had to do 2 things:

  1. Transform State[S,  A] into a type wit single parameter: λ[A]
  2. Don't loose the constraint of type S, so using a sort of closure on the type definition.
So what we have said is that we want λ[A] to be an alias for State[S, A] and because λ[A] is of type M[_] the compiler is not complaining. Note that I couldn't define the type λ in another expression because the definition of λ is using the type S, so if you remember our talk about closure on function parameters here we see the same trick but used on types, isn't that cool?

Saturday 13 December 2014

Demistify the State Monad with Scala 2/2

In the previous post we have explored how to define a Stack data structure and we have defined methods to pull and pop from that. All the methods accept the current stack and return a tuple containing the result of the operation and the new stack. We defined that kind of signature:

type State[S, A] = S => (A, S)

So here is where we are:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package fp

object StackApp extends App {

  type Stack[A] = List[A]
  type State[S, A] = S => (A, S)
  
  def push[A](a:A) : State[Stack[A], Unit] = stack => ((), a :: stack)
  
  def pop[A]: State[Stack[A], Option[A]] = {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }
  
  def popPairs[A]: State[Stack[A],(Option[A], Option[A])] = stack => {
    val (opt1, stack1) = pop(stack)
    val (opt2, stack2) = pop(stack1)
    ((opt1, opt2), stack2)
  }
}

Now that we have defined the State our target is to avoid the expressions inside popPairs, where we need carefully to pass the right instance of stack on each expression.

In order to do that we should define methods to compose different state together, for this reason we are going to introduce the 2 key methods: map and flatMap.


def map[S, A, B](sa:State[S, A])(f:A=>B): State[S, B] = ???
def flatMap[S, A, B](sa:State[S, A])(f:A=>State[S, B]): State[S, B] = ???

Ok lets see how we can implement these methods.
Lets start with map. The first thing we have to consider is the return type, has to be a State[S, B], so in essence has to be a function of type:
Given an initial state I have to return a tuple of kind (b, newState)


def map[S, A, B](sa:State[S, A])(f:A=>B): State[S, B] = state => {
  ...
  (b, newState)
}

Lets look the full implementation and comment it:


1
2
3
4
def map[S, A, B](sa:State[S, A])(f:A=>B): State[S, B] = state => {
    val (a, newState) = sa(state)
    (f(a), newState)
  }

We are simply applying the input state to sa, the result of this operation is in line 2 a tuple with result a:A and a newState:S.
We can simply apply f:A=>B to a and return the new tuple (f(a), newState).
The result is a function that take a state as input and return a tuple (b:B, newState:S), respecting the State[S, B] signature.
Note:Is interesting the high level of abstraction we are using in this function. Map is an higher level function because we are not reasoning on the possible implementations and it turns to be more like a game where we are trying to match the types. Is surprising that there are no many possible implementations of map, the type signature is restricting the possible implementations.
Ok lets move now on flatMap. This method is very important for "composibility".
The only difference on the signature compared to map is that the function f is transforming directly into the final type.
Why is this so important ?
Well lets assume we have only map method, and we call map inside another map:


1
2
3
4
5
6
7
map(dummyState) { stack1 => 
    ...
    map(dummyState2) {
      ...
      (b, finalState)
    }
  }

Well by composing 2 map methods one inside the other the final return type will be:

State[S, State[S, B]]

which is not exactly what we wanted. The idea is to flatten the inner State[S, B] to have just:
State[S, B] as final result.

In order to do that we need a new function able to do a map operation and then flatten it, for this reason we call it flatMap:


1
2
3
4
def flatMap[S, A, B](sa:State[S, A])(f:A=>State[S, B]): State[S, B] = state => {
    val (a, newState) = sa(state)
    f(a)(newState)
  }

Here we go, as per map we apply the state to sa, then we take the value a and we pass it to the function f.
This time f will return a new State[S, B], which is not good as return type because we need to return the tuple (b:B, s:State),  but because f(a) : State[S, B] we just can apply the newState:S to get our desired result in line 3.

Now that we have flatMap and map we can use them in the popPairs:


def popPairs[A]: State[Stack[A],(Option[A], Option[A])] =
    flatMap(pop[A]) ( opt1 => map(pop[A]) ( opt2 => (opt1, opt2) ) )

Here we go, with flatMap and map we are manipulating the State object obtained  from the pop call but now we don't have to bother with the states.

Lets try to improve the syntax.
The next step is to promote the State[S, A], from a simple alias to a propert trait with the map and flatMap methods part of it.


1
2
3
4
5
trait State[S, A] {
    def apply(s:S): (A, S)
    def map[B](f:A =>B): State[S, B]
    def flatMap[B](f:A=>State[S, B]): State[S, B]
  }

Now lets define a companion object for State and a factory method, we will also define the map and flatMap implementation.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
trait State[S, A] {
    def apply(s:S): (A, S)
    def map[B](f:A =>B): State[S, B] = State { s => 
     val (a, newState) = this(s)
     (f(a), newState)
    }
    def flatMap[B](f:A=>State[S, B]): State[S, B] = State { s => 
     val (a, newState) = this(s)
     f(a)(newState)
    }
  }
  
  object State {
    def apply[S, A](r: S => (A, S)): State[S, A] = new State[S, A] {
      def apply(s:S) = r(s)
    }
  }

So now map and flatMap are methods of the State trait, also the companion object State has a factory method that create a new state using a function of type S => (A, S).

Now our code will look like the below:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package fp

object StackApp extends App {

  type Stack[A] = List[A]
  
  trait State[S, A] {
    def apply(s:S): (A, S)
    def map[B](f:A =>B): State[S, B] = State { s => 
     val (a, newState) = this(s)
     (f(a), newState)
    }
    def flatMap[B](f:A=>State[S, B]): State[S, B] = State { s => 
     val (a, newState) = this(s)
     f(a)(newState)
    }
  }
  
  object State {
    def apply[S, A](r: S => (A, S)): State[S, A] = new State[S, A] {
      def apply(s:S) = r(s)
    }
  }
  
  def push[A](a:A) : State[Stack[A], Unit] = State { stack => ((), a :: stack) }
  
  def pop[A]: State[Stack[A], Option[A]] = State {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }
  
  def popPairs[A]: State[Stack[A],(Option[A], Option[A])] =
    pop[A].flatMap(opt1 => pop[A].map(opt2 => (opt1, opt2) ))
    
}

Fantastic now our popPairs uses the dot notation and looks more similar to object oriented programming style but is still not optimal.

In scala all the expressions where composibility is used (flatMap of flatMap of .... map) can be translated in a for comprehension expression.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def popPairs[A]: State[Stack[A],(Option[A], Option[A])] =
  pop[A].flatMap(opt1 => pop[A].map(opt2 => (opt1, opt2) ))

/**
 * IS EQUIVALENT TO :
 */
    
def popPairs[A]: State[Stack[A], (Option[A], Option[A])] = for {
  opt1 <- pop[A]
  opt2 <- pop[A]
} yield (opt1, opt2)

The second version is similar to imperative programming style but is in reality syntactical sugar of the first version.

So finally our code is:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package fp

object StackApp extends App {

  type Stack[A] = List[A]
  
  trait State[S, A] {
    def apply(s:S): (A, S)
    def map[B](f:A =>B): State[S, B] = State { s => 
     val (a, newState) = this(s)
     (f(a), newState)
    }
    def flatMap[B](f:A=>State[S, B]): State[S, B] = State { s => 
     val (a, newState) = this(s)
     f(a)(newState)
    }
  }
  
  object State {
    def apply[S, A](r: S => (A, S)): State[S, A] = new State[S, A] {
      def apply(s:S) = r(s)
    }
  }
  
  def push[A](a:A) : State[Stack[A], Unit] = State { stack => ((), a :: stack) }
  
  def pop[A]: State[Stack[A], Option[A]] = State {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }
  
  def popPairs[A]: State[Stack[A],(Option[A], Option[A])] = for {
    opt1 <- pop[A]
    opt2 <- pop[A]
  } yield (opt1, opt2)
  
}

As you can see we are not dealing anymore with the states in popPairs and the code is quiet intuitive and similar on how it would look in imperative style.

The benefit of using the State[S, A] is that none of these functions are manipulating the state, they are actually pushing the state modification to the very up of your stack so all these functions are PURE, this will give to your program an important property: Reference Transparency and in distributed system it can be extended to Location Transparency, very important for system which requires high availability and fault tolerance, aspects that we will cover on the next post, when we will use the State monad to implement a Key Value Store.



Demistify the State Monad with Scala 1/2

In this post I would like to introduce the concept of Monad with a simple example.

Ok lets start...

Let's create a data structure for Stacks and in pure functional programming style having methods to push and pop elements into the stack.

Step 1: we can use the List to implement a Stack:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package fp

object StackApp extends App {

  type Stack[A] = List[A]
  
  def push[A](a:A, stack:Stack[A]): Stack[A] = a :: stack
  
  def pop[A](stack:Stack[A]): (Option[A], Stack[A]) = stack match {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }
  
}

Because we have immutable data, methods push and pop have to return a new Stack after a push and pop operation on the input stack.

Now lets assume we want to define a new business method, called: popPairs, this method accept a stack and try to pop 2 elements, the result will be a tuple of Option[A] and the new stack after the pop operation.


1
2
3
4
5
  def popPairs[A](stack:Stack[A]): ((Option[A], Option[A]), Stack[A]) = {
    val (opt1, stack1) = pop(stack)
    val (opt2, stack2) = pop(stack1)
    ((opt1, opt2), stack2)
  }


Ok now lets try to use our methods and see how we can build new functions from existing ones.
I want a function pushZero which given a stack of Int will add a 0 on top of the stack and I want to reuse the push function. In order to do that I must use Currying syntax in scala and I have to modify the push signature as per below:


1
2
3
4
5
6
7
def push[A](a:A)(stack:Stack[A]): Stack[A]  = a :: stack
...
val pushZero = push(0)(_)
...
val myStack:Stack[Int] = 1::2::3::Nil

val newStack = pushZero(myStack)

The key question here is: what's the type of the val pushZero ?
pushZero is like push where the first argument of the function has been already passed but didn't get yet the second.

The only possible answer to that question is: pushZero: Stack[Int] => Stack[Int]

The call to push(0)(_) will return a new function which only require a Stack[Int] argument to be passed in order to produce a new Stack.

Finally in line 7 we will get the final result, so pushZero is just delaying the execution of pop once all the parameters have been provisioned.

Based on the above I personally prefer not do adopt the Scala Currying syntax and like in Haskell be more honest on the function signature, in fact with a simple trick we can move the Stack[A] parameter on the right side of the colon, making it part of the return type:


1
def push[A](a:A):  Stack[A] => Stack[A]  = stack => a :: stack

So now push accept one argument of type A and return a function that accept a Stack[A] and returns a Stack[A]. The implementation of the function is a lambda expression which will pre-append the a:A element.
Note:  the lambda expression accept as input parameter the stack, but in the body we also use the a:A value coming from the push signature, this mechanism is called closure.

After this change also the currying syntax will become more elegant and the code we have seen in the previous block will now look like this:


1
2
3
4
5
6
7
def push[A](a:A):  Stack[A] => Stack[A]  = stack => a :: stack
...
val pushZero = push(0) // pushZero is type of Stack[Int] => Stack[Int]
...
val myStack = 1::2::3::Nil

val newStack = pushZero(myStack)

Now that we understood the beta reduction, lets apply this concept to all our methods:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package fp

object StackApp extends App {

  type Stack[A] = List[A]
  
  def push[A](a:A) : Stack[A] => Stack[A] = stack => a :: stack
  
  def pop[A]: Stack[A] => (Option[A], Stack[A]) = {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }
  
  def popPairs[A]: Stack[A] => ((Option[A], Option[A]), Stack[A]) = stack => {
    val (opt1, stack1) = pop(stack)
    val (opt2, stack2) = pop(stack1)
    ((opt1, opt2), stack2)
  }
}

Something to note here is the change in line 9. pop[A] is a partial function. The concept is very similar to the Erlang language, so this function will do pattern matching on its arguments using the case statement in the body. If the input parameter doesn't match with any of the case statement, an exception will be thrown.

Essentially these 2 syntaxes are equivalent:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def pop[A]: Stack[A] => (Option[A], Stack[A]) = {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }

// is equivalent to:

def pop[A]: Stack[A] => (Option[A], Stack[A]) = stack => stack match {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }

But as you can see the second pop[A] definition declare an input parameter stack that is just be used in a match statement, there is no real need to have the stack input variables so Scala optimise this syntax by using the concept of Partial Functions.

Ok now that all our functions went through the beta reduction, lets reason on their signatures. First of all the push function is a setter method, is in essence a method that modify an object without returning a new value. Because we like honest functions and more importantly to make the signature consistent with the other methods we can say that push will return a tuple of (Unit, Stack[A]), where the first element of the tuple is the result of this operation (void in scala = Unit) and the second is the new status of the stack:


def push[A](a:A): Stack[A] => (Unit, Stack[A]) = stack => ((), a :: stack)

Ok now lets have a look on how all our program looks like:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package fp

object StackApp extends App {

  type Stack[A] = List[A]
  
  def push[A](a:A) : Stack[A] => (Unit, Stack[A]) = stack => ((), a :: stack)
  
  def pop[A]: Stack[A] => (Option[A], Stack[A]) = {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }
  
  def popPairs[A]: Stack[A] => ((Option[A], Option[A]), Stack[A]) = stack => {
    val (opt1, stack1) = pop(stack)
    val (opt2, stack2) = pop(stack1)
    ((opt1, opt2), stack2)
  }
}

Have a look on the return type of our methods, they share a common pattern.
All of them accept the current status (Stack[A]) and they return as result a tuple where the first element is the  result of the method application and the second element is the new status ( the new Stack[A] after the function has been applied).

So we can define a new entity which we will call State[S, A] as the following:


type State[S, A] = S => (A, S)

State[S, A] is just an alias for a function that given an S return a (A, S).
Lets apply State on our function return types:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package fp

object StackApp extends App {

  type Stack[A] = List[A]
  type State[S, A] = S => (A, S)
  
  def push[A](a:A) : State[Stack[A], Unit] = stack => ((), a :: stack)
  
  def pop[A]: State[Stack[A], Option[A]] = {
    case a :: tail => (Some(a), tail)
    case Nil       => (None, Nil)
  }
  
  def popPairs[A]: State[Stack[A],(Option[A], Option[A])] = stack => {
    val (opt1, stack1) = pop(stack)
    val (opt2, stack2) = pop(stack1)
    ((opt1, opt2), stack2)
  }
}

Fantastic, so State is nothing else than an alias of a function that given the current status will produce a result of type A and a new status.

What can we do with State ?

Well the power of programming is composition, the ability to combine different operations together in order to obtain our target result.
My target is to avoid to write the code inside popPairs, that code is error prone because I have to be careful to always look at the stack returned by the previous function call and use it in the new expression.

Now that we have introduced the concept of state, on the next post we will see how we can define operations over the State[S, A] and how to promote it from a type alias to a Type Class (Trait).

Continue to read the second part here.