Skip to content

Instantly share code, notes, and snippets.

@sungjk
Last active April 30, 2018 09:06
Show Gist options
  • Save sungjk/d936090f04aa7ad3c4a25e28613392eb to your computer and use it in GitHub Desktop.
Save sungjk/d936090f04aa7ad3c4a25e28613392eb to your computer and use it in GitHub Desktop.
MonadTransformer
import scala.concurrent.Future
import scala.language.higherKinds
sealed trait Monad[T[_]] {
def map[A, B](value: T[A])(f: A => B): T[B]
def flatMap[A, B](value: T[A])(f: A => T[B]): T[B]
def pure[A](x: A): T[A]
}
object MonadT {
case class OptionT[T[_], A](value: T[Option[A]])(implicit m: Monad[T]) {
def map[B](f: A => B): OptionT[T, B] = OptionT[T, B](m.map(value)(_.map(f)))
def flatMap[B](f: A => OptionT[T, B]): OptionT[T, B] = {
val result: T[Option[B]] = m.flatMap(value) { a => a.map(b => f(b).value).getOrElse(m.pure(None)) }
OptionT[T, B](result)
}
}
}
@sungjk
Copy link
Author

sungjk commented Apr 26, 2018

Test on repl

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global

import MonadT._

implicit val FutureMonad: Monad[Future] = new Monad[Future] {
    def map[A, B](value: Future[A])(f: A => B): Future[B] = value.map(f)

    def flatMap[A, B](value: Future[A])(f: A => Future[B]): Future[B] = value.flatMap(f)

    def pure[A](x: A): Future[A] = Future(x)
}

val one: OptionT[Future, Int] = OptionT(Future(Option(1)))
val two: OptionT[Future, Int] = OptionT(Future(Option(2)))

val sum = for {
    resultOne <- one
    resultTwo <- two
} yield {
    resultOne + resultTwo
}

Await.result(sum.value, Duration.Inf)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment