Skip to content

Instantly share code, notes, and snippets.

@jto
Created August 27, 2013 12:53
Show Gist options
  • Save jto/6353127 to your computer and use it in GitHub Desktop.
Save jto/6353127 to your computer and use it in GitHub Desktop.
ZRM about Monads
// http://slid.es/julientournay/a-monad-is-just-a-monoid-in-the-category-of-endofunctors-what-s-the-problem
trait Functor[F[_]] {
def map[Y, Z](x: F[Y])(f: Y => Z): F[Z]
}
trait ListFunctor extends Functor[List] {
def map[Y, Z](xs: List[Y])(f: Y => Z) = xs.map(f)
}
object ListFunctor extends ListFunctor
ListFunctor.map(List(1, 2, 3))(_ + 4)
trait Monoid[S] {
def zero: S
def append(a: S, b: S): S
}
object IntPlusMonoid extends Monoid[Int] {
def zero: Int = 0
def append(a: Int, b: Int): Int = a + b
}
val plus = IntPlusMonoid.append(3, 6)
object IntTimesMonoid extends Monoid[Int] {
def zero: Int = 1
def append(a: Int, b: Int): Int = a * b
}
val times = IntTimesMonoid.append(3, 6)
trait Monad[M[_]] extends Functor[M]{
def unit[X](x: X): M[X]
def join[X](mx: M[M[X]]): M[X]
def bind[X, Y](a: M[X])(f: X => M[Y]): M[Y] =
join(map(a)(f))
}
object ListMonad extends ListFunctor with Monad[List] {
def unit[X](x: X): List[X] = List(x)
def join[X](mx: List[List[X]]): List[X] = mx.flatten
}
trait ListMonadOps[X] {
val value: List[X]
def >>=[Y](f: X => List[Y]) = ListMonad.bind(value)(f)
}
implicit def toMonadOps[A](xs: List[A]) = new ListMonadOps[A] {
override val value = xs
}
val evens: Int => List[Int] = {
case x if x % 2 == 0 => List(x)
case _ => List()
}
val morethan5: Int => List[Int] = {
case x if x > 5 => List(x)
case _ => List()
}
val toStrings: Int => List[String] = { x => List("_" + x.toString + "_")}
List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) >>= evens >>= morethan5 >>= toStrings
def sequence[M[_], A](as: List[M[A]](implicit m: Monad[M]): M[List[A]] = {
val reversed = as.foldLeft[M[List[A]]](m.unit(Nil)){ (acc, ma) =>
m.bind(ma){ a: A =>
m.bind(acc){ as: List[A] =>
m.unit(a :: as)
}
}
}
m.bind(reversed){ as: List[A] => m.unit(as.reverse)
}
}
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
trait FutureFunctor extends Functor[Future] {
def map[Y, Z](ex: Future[Y])(f: Y => Z) = ex.map(f)
}
implicit object FutureMonad extends FutureFunctor with Monad[Future] {
def unit[X](x: X): Future[X] = Future.successful(x)
def join[X](mx: Future[Future[X]]): Future[X] = mx.flatMap(identity)
}
val fs: List[Future[Int]] = List(1, 2, 3, 4, 5).map(FutureMonad.unit)
Await.result(sequence(fs, FutureMonad), 1 seconds)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment