Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala case class with function parameters

Tags:

scala

I'm working with this code:

case class State[S, +A](run: S => (A, S)) {
  ...                                          
  def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => {    
    val (a, s1) = run(s)
    f(a).run(s1)
  })
  ...                                        
}

This is an abstraction for working with purely functional state, from §6 of FP in Scala. run is function parameter that takes a state and emits a tuple of a value and the new state.

My question is around the syntax s => in this section:

... B] = State(s => { ...

This appears to be using the State 'constructor' (ie apply) to build a new State object. But what does the s represent? Is it an 'anonymous' State, representing any State instance? If so, how is it different from this? Or does s correspond to the input parameter of run ie the S from:

... (run: S => ....  

And why would I be using a constructor for a function definition? Notice that the last symbol of the flatMap definition is a ) not a }, that is closing the State apply constructor.

This scenario is a bit different than the standard

case class Person(name: String)

scenario, so I thought I'd ask...

like image 847
Sonia Hamilton Avatar asked Mar 01 '15 07:03

Sonia Hamilton


1 Answers

Your second assumption is correct, s corresponds to the input parameter of run function, ie the S, which represents an actual state passing through the chain. So s => {...} is just a lambda definition of type S => (A, S). Lambdas and functions in Scala are first-class citizens (values), so you can pass them as parameters to hold inside some another type (including some monad).

Here the function, which produces new raw state S (and new result A), is wrapped (see return operation) to the monad State, which is implemented as case class. We need it to define flatMap operation (see bind) over the monad.

To make it more clear about the passing function as parameter, the code may be rewritten to:

case class State[S, +A](run: S => (A, S)) {
    def flatMap[B](f: A => State[S, B]): State[S, B] = {
        def newState(s: S) = {    
           val (a, s1) = run(s)
           f(a).run(s1)
        }
        State(newState _)
    }
}

So, according to the monad definition:

  • State[S, +A] is a type constructor which takes two plain types (S and covariant A) and returns monadic type State
  • State.apply(run: S => (A, S)) function takes a plain function and returns (lifts into) monadic container State, so it is a "return" operator of the monad
  • State.flatMap[B](f: A => State[S, B]): State[S, B] is corresponding to the "bind" operator

Case class is used just to have explicit "return" function (apply) instead of using new operator.

like image 89
dk14 Avatar answered Sep 21 '22 05:09

dk14