Skip to content

Instantly share code, notes, and snippets.

@chrislewis
Created March 11, 2012 23:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save chrislewis/2018679 to your computer and use it in GitHub Desktop.
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
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