object StateMonadExample {
def main(args: Array[String]) {
val startlist = List(1,2,3,4,5)
val finalstate = stateParse
val resultingList = finalstate ! startlist
println(resultingList)
if(resultingList == List(-1, 3, -3, 5, -5))
println("success")
else
println("fail!")
}
def stateParse: State[List[Int], List[Int]] = state[List[Int], List[Int]]( list => {
list.headOption match {
case None =>
(list, List[Int]()) //lets not infinitely recurse
case Some(i:Int) if (i%2 == 0) =>
(for(a <- pullAndAdd;
b <- stateParse)
yield(a :: b))(list)
case _ =>
(for(a <- pullAndInvert;
b <- stateParse)
yield (a :: b))(list)
}
})
def pullAndInvert = state[List[Int], Int](li => (li.tail, -li.headOption.getOrElse(0)))
def pullAndAdd = state[List[Int], Int](li => (li.tail, 1+li.headOption.getOrElse(0)))
/* copied from Scalaz for convenience */
sealed trait State[S, +A] {
def apply(s: S): (S, A)
def state[S, A](f: S => (S, A)): State[S, A] = new State[S, A] {
def apply(s: S) = f(s)
}
def map[B](f: A => B): State[S, B] = state(apply(_) match {
case (s, a) => (s, f(a))
})
def flatMap[B](f: A => State[S, B]): State[S, B] = state(apply(_) match {
case (s, a) => f(a)(s)
})
def !(s: S): A = apply(s)._2
def ~>(s: S): S = apply(s)._1
def withs(f: S => S): State[S, A] = state(f andThen (apply(_)))
}
def state[S, A](f: S => (S, A)): State[S, A] = new State[S, A] {
def apply(s: S) = f(s)
}
}