Search code examples
scalafunctional-programmingscalazstate-monad

How to apply a list of modifciations on a scalaz State Monad without for comprehension


I am currently playing arround with the scalaz State Monad. I want to implement a processing pipeline where a dynamic number of modifications will be applied to an initial State. I want to get out a final State after all processings have been done.

Here is a better graphical example.

                       +-------+        +-------+        +-------+
                       |       |        |       |        |       |
Initial State  +-----> |   m1  | +----> |   m2  | +----> |   m3  | +----> Final State
                       |       |        |       |        |       |
                       +-------+        +-------+        +-------+

I came up with this code

import  scalaz._
import  Scalaz._

object Main2 {

  def main(args: Array[String]) {

    val m1 = State[String, Unit] { (x:String) =>(x + " " + x, () )}
    val m2 = State[String, Unit] { (x:String) =>(x.toUpperCase(), () )}
    val m3 = State[String, Unit] { (x:String) =>(x.toLowerCase(), () )}

    val finalState = for(
      _ <- m1;
      _ <- m2;
      f <- m3
    ) yield (f)

    println( finalState.run("Foo") )

  }

}

This works so far but i dont know the exact number of modiffications at compile time so i can not use a for comprehension.

What i need is this

import  scalaz._
import  Scalaz._

object Main2 {

  def main(args: Array[String]) {

    val m1 = State[String, Unit] { (x:String) =>(x + " " + x, () )}
    val m2 = State[String, Unit] { (x:String) =>(x.toUpperCase(), () )}
    val m3 = State[String, Unit] { (x:String) =>(x.toLowerCase(), () )}

    type MyState = State[String, Unit];

    val modifications = List[MyState](m1,m2,m3);

    modifications.???.run("Foo")

  }

}
  1. How can apply this list of stateful computations on my initial state Foo so it has the same effect as i would use a for comprehension ?
  2. How can i combine this with the use of error handling in a fail fast approach?

Would this be a better signature for my modifications in terms of error handling ?

 type ModificationType = StateT[Try, String, Unit]

Thanks for your help


Solution

  • Well, the easy way is something like

    modifications.reduceLeft((a: MyState, b:MyState) => a.flatMap(_ => b));
    

    which is essentially a rewrite of the for comprehension.

    It looks like scalaz also provides sequenceU which could also be used

    modifications.sequenceU
    

    but I'm not sure about that one. (I don't have scala compiler with me)

    For your second question, yes, that should provide you with what you need.