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...
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 monadState.flatMap[B](f: A => State[S, B]): State[S, B]
is corresponding to the "bind" operatorCase class is used just to have explicit "return" function (apply
) instead of using new
operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With