working with Kleisli, et al.

85 views
Skip to first unread message

eric

unread,
May 9, 2012, 4:14:10 PM5/9/12
to sca...@googlegroups.com
hi All,

I have been using the scalaz-seven library in a project I am working on, and have often found the need to build up types like Kleisli[IO,Env,Validation[String,StatusMessage]], which to me (who is quite the newbie here!) basically means to read some stuff from the Env, and do a little IO that may result in a success or failure. I don't know if this is a common construct, since I don't have much practice yet using scalaz, but I am finding it tricky to get guys like these to compose the way I would like.

To provide a more concrete example:

def foo: Kleisli[Option,Env,String]
def bar: String => Kleisli[IO,Env,Validation[String,StatusMessage]]
def snaz: StatusMessage => Validation[String,String]

def run: Kleisli[IO,Env,Validation[String,String]] =
  // some magic to take foo to bar to snaz

So I would have some run function that would use the above functions to take the resulting String in the Option from foo and pass it to bar, then take the StatusMessage from bar and pass it to snaz, where the return type of this run function would end up as: Kleisli[IO,Env,Validation[String,String]]. Maybe this isn't making a lot of sense, or seems rather contrived, but what I am most curious about is how to properly structure this kind of code so that it can compose together. Because really what I want to achieve is composing foo, bar, and snaz, but be able to do so with the Monads layered over top.

Is the above just incorrect, is there something I am just missing, or would it be more common to do all of the Env reading up-front so that, for instance, the foo and bar functions didn't have to know about the Env? I realize this may completely depend on the context of the program, but I want to get a sense of how to generally tackle problems like these. Any suggestions, feedback, or simple examples would be great! And if there is something that needs clarification, please just let me know.

Thanks!
 -Eric

Runar Bjarnason

unread,
May 11, 2012, 10:46:15 AM5/11/12
to sca...@googlegroups.com
If you bind `bar` to the String in `foo`, you have Kleisli[Option, Env, Kleisli[IO, Env, Validation[String, StatusMessage]]]. The only way to reconcile that is if you can turn Option into IO. That's definitely possible, you just throw an exception when the Option is None. So given Option ~> IO, you can flatten into Kleisli[IO, Validation[String, StatusMessage]]. Map _.flatMap(snaz) over that and Bob's your uncle.

Alternatively, convert the Option[String] to a Validation[String, String] then .pure[IO] it. That gives you a Kleisli[IO, Env, Validation[String, String]]. Then flatMap(bar).map(_.flatMap(snaz)).

Is there a nicer way to automate moving through this monad stack? To be honest, your best bet in Scala is to create your whole stack as a new data type and write your own monad (and applicative) instance for it:

case class AppStack[A](f: Env => IO[Validation[String, A]])

def liftValidation[A](v: Validation[String, A]): AppStack[A] =
  AppStack(e => v.point)

Then you can just do:

for {
  s <- foo
  m <- bar(s)
  z <- liftValidation(snaz(m))
} yield z



 -Eric

--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To view this discussion on the web visit https://groups.google.com/d/msg/scalaz/-/qyEBwLousiwJ.
To post to this group, send email to sca...@googlegroups.com.
To unsubscribe from this group, send email to scalaz+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scalaz?hl=en.

eric

unread,
May 12, 2012, 8:40:11 AM5/12/12
to sca...@googlegroups.com
hi Runar,

This is great, thank you for your response! I really like the AppStack suggestion and I have an implementation of it in a gist for reference. Your advice really helped. Intuition on how to move through the monad stack was just what I was looking for.

Cheers,
 -Eric
To unsubscribe from this group, send email to scalaz+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages