Help with using the State Monad elegantly

39 views
Skip to first unread message

Vincent Marquez

unread,
Nov 16, 2012, 1:18:05 PM11/16/12
to scala...@googlegroups.com
I'm playing around with Scalaz' State class, seems very nice for certain use cases, however I'm not sure i'm using it in the 'correct' way, if not an elegant way. 

In my example I have a List[Int], and I simply want to generate a new list, depending on certain criteria I will execute different transformations that also return state, along with recursing till the end of the list. 

 Rather than having to deal with passing tuples around and all that jazz, using State is much nicer!  However, it is a bit weird that i'm calling 'apply' inside something that returns state to recurse.  

I feel like i'm probably missing something basic, so advice would be appreciated!  I do realize there are easier ways to 'map' a list, this just seemed like a good exercise that could represent more complex data structures.   Any suggestions appreciated, thanks in advance!

--Vincent






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)

    }


}

Reply all
Reply to author
Forward
0 new messages