Let’s talk monads again. And this time, I will show you the either monad. We’ll use it to model a process whose steps can fail; and we wish to abort the process whenever a step fails (and return the failures) and we wish to continue the process if the step succeeds.
The practical application is to use the either monad is code that prepares some HTTP requests, sends the requests and then parses the responses. In pseudo-code, we have:
prepare: S => Either[Errors, Payload] request: Payload => Either[Errors, Payload] parse: Payload => Either[Errors, R]
Where S is some starting type and R is the final return type. As you can probably tell, the entire operation is
op: S => Either[Errors, R]
We now want to bind the three steps into the final op: the either monad will allow a value on the right to flow through the operation, while a value on the left will stop the process and immediately be returned. Still keeping with pseudo-code, we assemble the beast as
op(source: S) = prepare(source) >>= request >>= parse
The notion of a workflow helps; indeed, the operation op is best imagined as simple operation followed by decision:

Adding some type annotations will make the flow of values even clearer:

Right. Let’s turn on the real syntax and type up some almost complete Scala code:
import scalaz._
import Scalaz._
sealed trait Failure
case class ServiceUnavailable(message: String) extends Failure
case class TheSonsOfKhanAreRebelling() extends Failure
// and more to taste
case class Payload(contentType: String, body: String)
case class Input(...)
case class ParserSettings(...)
def work(input: Input, parserSettings: ParserSettings):
Either[Seq[Failure], Integer] = {
def prepare(input: Input): Either[Seq[Failure], Payload] = {
// do some work, ultimately hopefully
Right(Payload("application/json", "..."))
}
def request(payload: Payload): Either[Seq[Failure], Payload] = {
// prepare request
val httpClient = new DefaultHttpClient()
val post = new HttpPost("/location/to/post")
// make the entity
val entity = new StringEntity(payload.body)
entity.setContentType(payload.contentType)
post.setEntity(entity)
// perform the post
try {
httpClient.execute(new HttpHost("localhost", 80, "http"),
post, new ResponseHandler[Either[Seq[Failure], Payload] {
def handleResponse(response: HttpResponse) = {
val entity = response.getEntity
// process the input, ultimately returning
Right(Payload("application/json", "...")
}
})
} catch {
case e: Exception => Left(ServiceUnavailable(e.getMessage) :: Nil)
}
}
def parse(parserSettings: ParserSettings)
(payload: Payload): Either[Seq[Failure], Integer] = {
// use the parserSettings, but ultimately, parse and
// somehow calculate, returning from the payload
Right(42)
}
// We now have the three steps. Let's bind them together.
prepare(input) >>= request >>= parse(parserSettings)
}
And so, using the either monad in Scalaz 6, we have bound together our functions into a workflow-like structure. The behaviour of the either monad (either monad because the return type of the steps is Either[_, _]) stops & returns whenever a step returns a value on the left and continues to the next step, passing the returned value on the right from the previous step to it.
The end result is nicely readable code and less work for you to propagate—in this particular case—failures.

Jan,
You’re implying that Either is being provided by Scalaz, but I’m pretty sure it ain’t. In fact, I’m not sure that Scalaz is being used at all in this snippet.
Rob
Hi Rob,
It is using Scalaz–what you’re seeing is implicit conversion of the functions prepare, request and parse into the monad and bound together with >>=. (If you don’t believe me, remove the import scalaz._; import Scalaz._ and see if it still compiles
)
Jan
Oops. Now I see.
Sorry!
No worries–it’s just the >>= that is easily lost in the rest of the text, but that delivers the bang
Jan
Oh nice, normally if you use for comprehensions you need to use a right projection?
Scalaz7 M2 has a right-biased Either to replace scala.Either btw
How about moving the imports to just before you use >>=?
Otherwise, it’s hard work to understand where things are coming from.
And it might even compile a bit faster!
That’s a good idea; and I’ll take faster compilation any time.
Thanks!
Jan
Jan,
Thank you very much. Your posts are always very helpful.
Every Friday morning, I looked forward to the “This Week in Scala” series. Have you guys decided to stop it, or is just a summer vacation thing?
Thanks,
Keith.
Hi Keith,
Thanks for your comment–people were on holiday, but we’re back with the weekly scala post starting today!
Jan
Gr8!! You cannot imagine how many times I click “refresh” on Friday mornings!
Pingback: This week in #Scala (17/08/2012)? | Cake Solutions Team Blog
@Rob Dickens
Can you, please, say more how position of import statement affects compilation times?
Hi, I’m afraid I’m not qualified to say anything on this – my suggestion was based purely on intuition, rather than knowledge of how the Scala compiler works.
Try the mailing lists – it would be good to find out.
Completely unscientific measurement (sample size 5, just one computer, Friday morning, …) comes out as (whole project compile times, without tests):
import at the compilation unit level: 1:53.119s
import at inside the function: 1:54.044s
Intuitively, there should be some difference, but in a large project, it doesn’t make much difference because of all the other stuff that needs compiling.