Created
March 29, 2016 17:45
-
-
Save juanjovazquez/c8bf51d9c4b4e518c65cfef43e03e61f to your computer and use it in GitHub Desktop.
Translation of Raul Raja's article `FP for the average Joe - II - ScalaZ Monad Transformers` for using cats library instead of scalaz. @see http://bit.ly/1SkmOTe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| Translation of Raul Raja's article | |
| `FP for the average Joe - II - ScalaZ Monad Transformers` | |
| for using cats library instead of scalaz. | |
| @see http://bit.ly/1SkmOTe | |
| */ | |
| package joe | |
| object Domain { | |
| case class Country(code: Option[String]) | |
| case class Address(addressId: String, country: Option[Country]) | |
| case class Person(name: String, address: Option[Address]) | |
| } | |
| object MonadTrans_1 { | |
| import Domain._ | |
| def getCountryCode(maybePerson: Option[Person]): Option[String] = | |
| maybePerson flatMap { person => | |
| person.address flatMap { address => | |
| address.country flatMap { country => | |
| country.code | |
| } | |
| } | |
| } | |
| } | |
| object MonadTrans_2 { | |
| import Domain._ | |
| def getCountryCode(maybePerson: Option[Person]): Option[String] = for { | |
| person <- maybePerson | |
| address <- person.address | |
| country <- address.country | |
| code <- country.code | |
| } yield code | |
| } | |
| object LocationService { | |
| import Domain._ | |
| import scala.concurrent.Future | |
| def findPerson(id: String): Future[Option[Person]] = ??? | |
| def findCountry(addressId: String): Future[Option[Country]] = ??? | |
| } | |
| object MonadTrans_3 { | |
| import Domain._ | |
| import LocationService._ | |
| import scala.concurrent.ExecutionContext.Implicits.global | |
| // This does not compose as we could expect. | |
| def getCountryCode(personId: String) = | |
| findPerson(personId) map { maybePerson => | |
| maybePerson map { person => | |
| person.address map { address => | |
| findCountry(address.addressId) map { maybeCountry => | |
| maybeCountry map { country => | |
| country.code | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| object MonadTrans_4 { | |
| import Domain._ | |
| import LocationService._ | |
| import scala.concurrent.Future | |
| import scala.concurrent.ExecutionContext.Implicits.global | |
| // This gives us some warning as partial matches are | |
| // not exhaustive. | |
| def getCountryCode(personId: String): Future[Option[String]] = | |
| findPerson(personId) flatMap { case Some(Person(_, Some(address))) => | |
| findCountry(address.addressId) map { case Some(Country(code)) => | |
| code | |
| } | |
| } | |
| } | |
| object MonadTrans_5 { | |
| import Domain._ | |
| import LocationService._ | |
| import scala.concurrent.Future | |
| import scala.concurrent.ExecutionContext.Implicits.global | |
| def getCountryCode(personId: String): Future[Option[String]] = for { | |
| maybePerson <- findPerson(personId) | |
| person <- Future.successful { | |
| maybePerson getOrElse (throw new NoSuchElementException) | |
| } | |
| address <- Future.successful { | |
| person.address getOrElse (throw new NoSuchElementException) | |
| } | |
| maybeCountry <- findCountry(address.addressId) | |
| country <- Future.successful { | |
| maybeCountry getOrElse (throw new NoSuchElementException) | |
| } | |
| } yield country.code | |
| } | |
| object MonadTrans_6 { | |
| import Domain._ | |
| import LocationService._ | |
| import cats.implicits._ | |
| import cats.data.OptionT | |
| import scala.concurrent.Future | |
| import scala.concurrent.ExecutionContext.Implicits.global | |
| def getCountryCode(personId: String): Future[Option[String]] = { | |
| val result: OptionT[Future, String] = for { | |
| person <- OptionT(findPerson(personId)) | |
| address <- OptionT(Future.successful(person.address)) | |
| country <- OptionT(findCountry(address.addressId)) | |
| code <- OptionT(Future.successful(country.code)) | |
| } yield code | |
| result.value | |
| } | |
| } | |
| object MonadTrans_7 { | |
| import Domain._ | |
| import LocationService._ | |
| import cats.implicits._ | |
| import cats.data.OptionT | |
| import scala.concurrent.Future | |
| import scala.concurrent.ExecutionContext.Implicits.global | |
| type Result[A] = OptionT[Future, A] | |
| object ? { | |
| def <~[A](v: Future[Option[A]]): Result[A] = OptionT(v) | |
| def <~[A](v: Option[A]): Result[A] = OptionT(Future.successful(v)) | |
| def <~[A](v: A): Result[A] = OptionT.pure(v) | |
| } | |
| def getCountryCode(personId: String): Future[Option[String]] = { | |
| val result: Result[String] = for { | |
| person <- ? <~ findPerson(personId) | |
| address <- ? <~ person.address | |
| country <- ? <~ findCountry(address.addressId) | |
| code <- ? <~ country.code | |
| } yield code | |
| result.value | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment