Skip to content

Instantly share code, notes, and snippets.

@juanjovazquez
Created March 29, 2016 17:45
Show Gist options
  • Select an option

  • Save juanjovazquez/c8bf51d9c4b4e518c65cfef43e03e61f to your computer and use it in GitHub Desktop.

Select an option

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
/**
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