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))
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)
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)
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)
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
^
//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")
}
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)
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)
def stackManip: State[Stack, Int] =
for {
_ <- push(3)
a <- pop
} yield(a)
scala> stackManip.run(l).value
res11: (Stack, Int) = (List(2, 1),3)
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),())
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),())
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))
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)
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)
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)
- | 1 |
---|---|
- | 2 |
- | 3 |
- | 4 |
- | 5 |
- | 6 |
- | 7 |
- | 8 |
- | 9 |
- | 10 |
- | 11 |
Exercise | 12 |
- | 13 |
- | 14 |
- | 15 |
- | 16 |
Table of Contents | t |
---|---|
Exposé | ESC |
Full screen slides | e |
Presenter View | p |
Source Files | s |
Slide Numbers | n |
Toggle screen blanking | b |
Show/hide slide context | c |
Notes | 2 |
Help | h |