-
-
Save gclaramunt/2019216 to your computer and use it in GitHub Desktop.
general type and implicit conversion to add support for using a general Monad in a for comprehension
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
trait Monad[M[_]] { | |
def unit[A](a: => A): M[A] | |
def fmap[A, B](ma: M[A], f: A => B): M[B] = bind(ma, (a:A) => unit(f(a))) | |
def bind[A, B](ma: M[A], f: A => M[B]): M[B] | |
} | |
/** A wrapper for any Monad instance for use in a for-comprehension. */ | |
abstract class Comprehensible[A, M[_] : Monad] { | |
def map[B](f: A => B): M[B] | |
def flatMap[B](f: A => M[B]): M[B] | |
} | |
/** Provide an implicit conversion to wrap any Monad in a for-comprehensible wrapper. */ | |
object Comprehensible { | |
implicit def comprehensibleMonad[A, M[_] : Monad](ma: M[A]) = new Comprehensible[A, M] { | |
val m = implicitly[Monad[M]] | |
def map[B](f: A => B): M[B] = m.fmap(ma, f) | |
def flatMap[B](f: A => M[B]): M[B] = m.bind(ma, f) | |
} | |
} | |
/** A basic IO action. */ | |
trait IO[A] { | |
def unsafePerformIO(): A | |
} | |
/** A constructor to wrap any A as an IO action (provide a unit in a Monad instance). */ | |
object IO { | |
def apply[A](a: => A) = new IO[A] { | |
override def unsafePerformIO() = a | |
} | |
} | |
/** An implicit monad instance. */ | |
implicit val monadIO = new Monad[IO] { | |
def unit[A](a: => A) = IO { a } | |
def bind[A, B](ma: IO[A], f: A => IO[B]): IO[B] = IO { | |
f(ma.unsafePerformIO()).unsafePerformIO() | |
} | |
} | |
/** Now we can use any type for which there exists a Monad instance in a for-comprehension. */ | |
import Comprehensible._ | |
/** We have a Monad for IO and Comprehensible in scope, so we can create an IO action in a for-comprehension without having to implement map/flatMap ad-hoc in IO. */ | |
val greetReadEcho = for { | |
_ <- IO { println("Type a character: ") } | |
c <- IO { System.console.readLine() } | |
_ <- IO { println("READ: " + c) } | |
} yield c | |
greetReadEcho.unsafePerformIO() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment