Created
March 11, 2012 23:32
-
-
Save chrislewis/2018679 to your computer and use it in GitHub Desktop.
general type and implicit conversion to add support for using a general Bind instance 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 Bind[M[_]] { | |
def fmap[A, B](ma: M[A], f: A => B): M[B] | |
def bind[A, B](ma: M[A], f: A => M[B]): M[B] | |
} | |
trait Monad[M[_]] extends Bind[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))) | |
} | |
/** A wrapper for any Bind instance for use in a for-comprehension. */ | |
abstract class Comprehensible[A, M[_] : Bind] { | |
def map[B](f: A => B): M[B] | |
def flatMap[B](f: A => M[B]): M[B] | |
} | |
/** Provide an implicit conversion to wrap any Bind in a for-comprehensible wrapper. */ | |
object Comprehensible { | |
implicit def impM[A, M[_] : Bind](ma: M[A]) = new Comprehensible[A, M] { | |
val m = implicitly[Bind[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, and therefore an instance of Bind. */ | |
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 Bind instance in a for-comprehension. */ | |
import Comprehensible._ | |
/** We have a Bind 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