StateM

The state effect enables purely functional state throughout programs.

The state effect supports parametrization to any type remaining type safe throughout the program declaration.

There needs to be implicit evidence of MonadState[M[_], S] for any runtime M[_] where S is the type of state due to the constraints placed by this effect.

The state effect comes with four basic operations get, set, modify, and inspect.

get

get retrieves the current state:

import freestyle._
// import freestyle._

import freestyle.implicits._
// import freestyle.implicits._

import freestyle.effects.state
// import freestyle.effects.state

import cats.data.State
// import cats.data.State

import cats.implicits._
// import cats.implicits._

val st = state[Int]
// st: freestyle.effects.state.StateSeedProvider[Int] = freestyle.effects.state$StateSeedProvider@1b5084f

type TargetState[A] = State[Int, A]
// defined type alias TargetState

import st.implicits._
// import st.implicits._

def programGet[F[_]: st.StateM] =
  for {
    a <- FreeS.pure(1)
    b <- st.StateM[F].get
    c <- FreeS.pure(1)
  } yield a + b + c
// programGet: [F[_]](implicit evidence$1: st.StateM[F])cats.free.Free[[β$0$]cats.free.FreeApplicative[F,β$0$],Int]

programGet[st.StateM.Op].interpret[TargetState].run(1).value
// res0: (Int, Int) = (1,3)

set

set replaces the current state:

def programSet[F[_]: st.StateM] =
  for {
    _ <- st.StateM[F].set(1)
    a <- st.StateM[F].get
  } yield a
// programSet: [F[_]](implicit evidence$1: st.StateM[F])cats.free.Free[[β$0$]cats.free.FreeApplicative[F,β$0$],Int]

programSet[st.StateM.Op].interpret[TargetState].run(0).value
// res1: (Int, Int) = (1,1)

modify

modify modifies the current state:

def programModify[F[_]: st.StateM] =
  for {
    a <- st.StateM[F].get
    _ <- st.StateM[F].modify(_ + a)
    b <- st.StateM[F].get
  } yield b
// programModify: [F[_]](implicit evidence$1: st.StateM[F])cats.free.Free[[β$0$]cats.free.FreeApplicative[F,β$0$],Int]

programModify[st.StateM.Op].interpret[TargetState].run(1).value
// res2: (Int, Int) = (2,2)

inspect

inspect runs a function over the current state and returns the resulting value:

def programInspect[F[_]: st.StateM] =
  for {
    a <- st.StateM[F].get
    b <- st.StateM[F].inspect(_ + a)
  } yield b
// programInspect: [F[_]](implicit evidence$1: st.StateM[F])cats.free.Free[[β$0$]cats.free.FreeApplicative[F,β$0$],Int]

programInspect[st.StateM.Op].interpret[TargetState].run(1).value
// res3: (Int, Int) = (1,2)