I have a Play! 2 for Scala application that needs to retrieve some data in JSON format from an external service.
The Play! framework allows to make HTTP requests asynchronously by wrapping the response in a Promise. Promise
is a monad that wraps a value that will be available in the future.
This is fine, but in my case what I get from the web service is a JSON string. I have to parse it and the parsing might fail. So I have to wrap whatever I get into an Option
. The result is that many of my methods are returning Promise[Option[Whatever]]
. That is, a value of type Whatever
that will be, maybe, available later.
Now whenever I have to operate over such a value I need to map
it twice. I was thinking of handling this in the following way:
- creating a new type, say
Hope[A]
, that wraps aPromise[Option[A]]
- defining the relevant methods like
map
(or maybe I should useforeach
and inherit from some collection trait?) andflatten
- provide an implicit converter between
Promise[Option[A]]
andHope[A]
.
It is easy to define map
- the composition of two functors is again a functor - and flatten
can be done explicitly in this case, or whenever composing a monad with Option
.
But it is my limited understanding that I do not need to reinvent this stuff: monad transformer exist for exactly this case. Or, well, so I think - I have never used a monad tranformer - and this is the point of the question:
Can monad tranformers be used in this situation? How would I go about actually using them?
Using the Scalaz library's
OptionT
transformer, you should be able to turn values of typePromise[Option[A]]
into values of typeOptionT[Promise, A]
.Using Scalaz 7:
To use this value, for example to call
map
orflatMap
on it, you will need to provide an appropriate typeclass forPromise
(Functor
formap
,Monad
forflatMap
).Since
Promise
is monadic, it should be possible to provide an instance ofMonad[Promise]
. (You'll getFunctor
andApplicative
for free, because the typeclasses form an inheritance hierarchy.) For example (note: I've not tested this!):As a simple example, you can now use
map
on theOptionT[Promise, A]
, to apply a function of typeA => B
to the value inside:To retrieve the underlying
Promise[Option[A]]
value from anOptionT[Promise, A]
, call therun
method.You will gain more benefit from using monad transformers when you can compose several operations of compatible types, preserving the
OptionT[Promise, _]
type between operations and retrieving the underlying value at the end.To compose operations in a for-comprehension, you will need functions of type
A => OptionT[Promise, B]
.-- removed --
edit:
Okay, you can simply use the
scalaz.OptionT
here: