Validating the future

270 views
Skip to first unread message

Timothy Perrett

unread,
Jan 22, 2013, 1:51:34 AM1/22/13
to sca...@googlegroups.com
Hey all,

So I was looking at something recently and wanted to take on some advice because it was a little awkward, and i'm not really that happy with how it worked out. Imagine there are two 3rd party service calls that are executed in Future blocks (they are akka futures), and I want to validate the results of those service calls, before using the results of said validation to execute another function in the success case. This "end" function must not be executed if the validation failed. 

Of course, lifting my functions that do validation into the future means that I end up with multiple Future[Validation[A,B]], and then loose out on the convenience of being able to short-circuit the computation (other than on a future completing in a failed state) or aggregate the validation results. I could implement traverse for Future and convert Future[Validation[A,B]] into Validation[A, Future[B]], but that would require me to block as far as i can see it, and i'd rather not block if possible.

Hope that makes some sense; does anyone else have a similar situation they've resolved this cleanly for? 

Cheers, Tim 

Stefan Hoeck

unread,
Jan 22, 2013, 3:26:52 AM1/22/13
to sca...@googlegroups.com
If your end function must not be executed if validation was invalid, you are probably better of with the \/-Monad. You can first accumulate errors of the two service calls via Future[Validation[A,B]] (via its applicative functor). Both functions will be executed and possible errors accumulated. Now transfer this to EitherT[Future,A,B] (which defines a monad) before calling the final function, which might be of the type B => EitherT[Future,A,C]. The final function will only be executed, if both service calls where successful. If the final function is a pure calculation from B to C you can user functor map instead of monadic bind. In that case, you can stick to Future[Validation[A,B]] since the final function will only be executed if the prior calculations were successful.

By the way, validations can easily be converted to \/ by calling the 'disjunction' function.

Does that make sense?

Chris Marshall

unread,
Jan 22, 2013, 3:35:10 AM1/22/13
to sca...@googlegroups.com
I don't get that you need blocking here. Surely you have the following:

  Stream[Future[Validation[E, A]]]

You want to sequence the outer Stream[Future] to get:

  Future[Stream[Validation[E, A]]]

Assuming E is a semigroup (e.g. NonEmptyList), you can then get to (by sequencing the inner Stream[Validation])

  Future[Validation[E, Stream[A]]]

All this is without blocking of course.

Chris



--
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/-/lfw3bvvTvToJ.
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.

Alec Zorab

unread,
Jan 22, 2013, 5:07:41 AM1/22/13
to sca...@googlegroups.com
type ValidationSNEL[T] = ValidationNEL[String, T]
type A
type B
type C
val app = Applicative[Future].compose[ValidationSNEL]
val f : (A, B) => C = ???
val output : Future[ValidationSNEL[C]] = app.apply2(a,b)(f)

no?

Alec Zorab

unread,
Jan 22, 2013, 5:09:09 AM1/22/13
to sca...@googlegroups.com
... of course, that means you need an applicative instance for Future. See, for example, https://github.com/robinp/akkaz for reference.

(apologies for the double post)

Lars Hupel

unread,
Jan 22, 2013, 6:09:37 AM1/22/13
to sca...@googlegroups.com
> ... of course, that means you need an applicative instance for Future. See,
> for example, https://github.com/robinp/akkaz for reference.

Or try <https://github.com/larsrh/scalaz-contrib>:

"org.typelevel" %% "scalaz-contrib-210" % "0.1"

This contains the same instances as akkaz, but is tested and published
on Maven Central.

Tony Morris

unread,
Jan 22, 2013, 7:07:45 AM1/22/13
to sca...@googlegroups.com

Go Lars you legend of phenomenal proportion.

Timothy Perrett

unread,
Jan 22, 2013, 11:09:25 AM1/22/13
to sca...@googlegroups.com
Hey Chris,

Thanks for the reply, but I don't get why you think that I must have a Stream enclosing the Future(s)? 

Cheers, Tim 

Richard Wallace

unread,
Jan 22, 2013, 12:12:22 PM1/22/13
to sca...@googlegroups.com
This is the approach I would take.  I suggested it on Twitter a while ago[1].  We use this approach in our code when we have to validate forms using side-effects (not with Future, but that is irrelevant), and it works quite nicely.

Tim, is there some reason this doesn't work in your case?

Chris Marshall

unread,
Jan 22, 2013, 2:44:06 PM1/22/13
to sca...@googlegroups.com, sca...@googlegroups.com
Because in your OP you said you had a number of them. Seems I misunderstood.

Chris
To view this discussion on the web visit https://groups.google.com/d/msg/scalaz/-/pdUo8wjpojoJ.

Timothy Perrett

unread,
Jan 22, 2013, 5:51:33 PM1/22/13
to sca...@googlegroups.com
Sure, I saw your comment and did start implementing Apply myself, but then occurred to me that there was probally someone that implemented the Apply/Traverse etc already so wanted to start a conversation about it :-)

I'll try this approach later tonight if I get home from work at a reasonable time.

Cheers, Tim 

Chris Marshall

unread,
Jan 23, 2013, 3:06:38 AM1/23/13
to sca...@googlegroups.com
Actually you said "I end up with multiple Future[Validation[A,B]]". So I took this to mean you had a "Stream[Future[Validation[A,B]]]"

I guess what you meant was that you had Future[Validation[A,B1]], Future[Validation[A,B2]], Future[Validation[A,B3]] etc etc and you want to change this into Future[Validation[A,(B1, B2, B3)]] without blocking. Luckily for you, applicative functors compose!

Chris

Timothy Perrett

unread,
Jan 29, 2013, 11:21:08 AM1/29/13
to sca...@googlegroups.com
Just to follow up on this thread - thanks for the pointers guys, Applicative[Future].compose was exactly what I needed :-)

Cheers, Tim 
Reply all
Reply to author
Forward
0 new messages