Presenter Notes

import cats._, cats.std.all._
import cats.syntax.eq._, cats.data.State, 
//case class State[S,+A](run: S => (S, A)){ ... }
def set[S](s: S): State[S, Unit] = 
  State(_ => (s, ()))
//set value
def pure[S, A](a: A): State[S, A] = 
  State(s => (s, a))
def get[S]: State[S, S] = 
  State(s => (s, s))

Presenter Notes

scala> val foo = get[Int]
foo: State[Int,Int] = StateT@30dfee57
scala> foo.run(1).value
res0: (Int, Int) = (1,1)
scala> foo.run(2).value
res1: (Int, Int) = (2,2)

Presenter Notes

scala> val bar = set(1)
s: State[Int,Unit] = StateT@b704c98
scala> bar.run(1).value
res2: (Int, Unit) = (1,())
scala> bar.run(2).value
res3: (Int, Unit) = (1,())
scala> bar.flatMap(_ => foo).run(2).value
res4: (Int, Int) = (1,1)

Presenter Notes

scala> val hi = bar.flatMap(_ => pure("hi"))
hi: StateT[Eval,Int,String] = StateT@13bdf906
scala> hi.map(_++" there").run(2).value
res5: (Int, String) = (1,hi there)

Presenter Notes

set doesn't add values

scala> def addOne(i: Int) = i+1
addOne: (i: Int)Int
scala> foo.map(addOne).run(1).value
res6: (Int, Int) = (1,2)
scala> bar.map(addOne).run(1).value 
<console>:33: error: type mismatch;
 found   : Int => Int
 required: Unit => ?
       bar.map(foo).run(1).value
         ^

Presenter Notes

//simple stack example
type Stack = List[Int]
def push(x: Int) = State[Stack, Unit] {
  case xs => (x :: xs, ())
}
val pop = State[Stack, Int] {
  case x :: xs => (xs, x)
  case Nil     => sys.error("empty")
}

Presenter Notes

scala> val l = List(2, 1)
l: List[Int] = List(2, 1)
scala> push(3).run(l).value
res7: (Stack, Unit) = (List(3, 2, 1),())
scala> pop.run(l).value
res8: (Stack, Int) = (List(1),2)

Presenter Notes

scala> push(3).flatMap( _ => pop.map(a => a+10))
res9: StateT[Eval,Stack,Int] = StateT@494f7a8
scala> res9.run(l).value
res10: (Stack, Int) = (List(2, 1),13)

Presenter Notes

def stackManip: State[Stack, Int] = 
  for {
    _ <- push(3)
    a <- pop
  } yield(a)

Presenter Notes

scala> stackManip.run(l).value
res11: (Stack, Int) = (List(2, 1),3)

Presenter Notes

def push1(x: Int): State[Stack, Unit] = 
  for {
    xs <- State.get[Stack]
    s <- State.set(x :: xs)
  } yield s



scala> push2(3).run(l).value res12: (Stack, Unit) = (List(3, 2, 1),())

Presenter Notes

Exercise

Work through this on paper using the substitution rule.

def push2(x: Int): State[Stack, Unit] = 
  State.get[Stack]
       .flatMap( xs => State.set(x :: xs))



scala> push2(3).run(l).value res13: (Stack, Unit) = (List(3, 2, 1),())

Presenter Notes

Presenter Notes

def set[S](s: S): State[S, Unit] = 
  State(_ => (s, ()))
def get[S]: State[S, S] = 
  State(s => (s, s))
def flatMap[B](f: A => State[S, B]): State[S, B] = 
  State(s => {
    val (a, s1) = run(s)
    f(a).run(s1)
  })
def push2(x: Int): State[Stack, Unit] = 
  State.get[Stack]
       .flatMap( xs => State.set(x :: xs))

Presenter Notes

val pop1: State[Stack, Int] = 
  for {
    s <- State.get[Stack]
    (x :: xs) = s
  } yield x



scala> pop1.runS(l).value res14: Stack = List(4, 3, 2, 1)

Presenter Notes

val pop2: State[Stack, Int] = 
  State.get[Stack]
       .flatMap(s => {
          val (x::xs) = s
          pure(x) //stack is stale
          })



scala> pop2.run(l).value res15: (Stack, Int) = (List(4, 3, 2, 1),4)

Presenter Notes

val pop3: State[Stack, Int] = 
  State.get[Stack].flatMap(s => {
    val (x::xs) = s
    State.set(xs).map(_ => x)

})



scala> pop3.run(l).value res16: (Stack, Int) = (List(3, 2, 1),4)

Presenter Notes