Created
November 1, 2015 14:49
-
-
Save missingfaktor/571cd29ce357b2367b22 to your computer and use it in GitHub Desktop.
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
| package sudoku.console | |
| object Monadology { | |
| // Wear the function goggles. | |
| val foo = 2 + 3 | |
| val bar = foo + 1 | |
| Math.min(foo, bar) | |
| // Start seeing let bindings as functions! | |
| def let[A, B](f: => A)(cont: A => B): B = cont(f) | |
| let(2 + 3) { foo => | |
| let(foo + 1) { bar => | |
| Math.min(foo, bar) | |
| } | |
| } | |
| // A, (A => B) => B | |
| // Nulls | |
| import java.util.{Map => JMap, HashMap => JHashMap, Arrays => JArrays} | |
| val mappa = new JHashMap[Int, String] { | |
| put(2, "two") | |
| put(3, "three") | |
| } | |
| // REAL WORLD!!!! | |
| // Nice code, but incorrect code | |
| val x = mappa.get(2) | |
| val y = mappa.get(x.length) | |
| x.concat(y) | |
| // Not so nice code, but correct code | |
| val x1 = mappa.get(2) | |
| if (x1 != null) { | |
| val y1 = mappa.get(x.length) | |
| if (y1 != null) { | |
| x.concat(y) | |
| } else { | |
| null | |
| } | |
| } else { | |
| null | |
| } | |
| // Null is barbaric. Let's use options. | |
| val mappa1 = Map(2 -> "two", 3 -> "three") | |
| // Not so nice code, even with Scala, but correct code | |
| mappa1.get(2) match { | |
| case Some(x) => | |
| mappa1.get(x.length) match { | |
| case Some(y) => Some(x.concat(y)) | |
| case None => None | |
| } | |
| case None => | |
| None | |
| } | |
| // Let's abstract! | |
| def ifNonNull[A, B](f: Option[A])(cont: A => Option[B]): Option[B] = { | |
| f match { | |
| case Some(a) => cont(a) | |
| case None => None | |
| } | |
| } | |
| ifNonNull(mappa1.get(2)) { x => | |
| ifNonNull(mappa1.get(x.length)) { y => | |
| Some(x.concat(y)) | |
| } | |
| } | |
| // Whoa. let and ifNonNull look similar! | |
| // let : Id[A], (A => Id[B]) => Id[B] | |
| // ifNonNull : Option[A], (A => Option[B]) => Option[B] | |
| // Both let and ifNonNull "bind" things! How they do it varies. | |
| trait Let[F[_]] { | |
| def let[A, B](f: F[A])(g: A => F[B]): F[B] | |
| def pull[A](a: A): F[A] | |
| } | |
| object Let { | |
| implicit val optionLet = new Let[Option] { | |
| override def let[A, B](f: Option[A])(g: (A) => Option[B]): Option[B] = f.flatMap(g) | |
| override def pull[A](a: A): Option[A] = Some(a) | |
| } | |
| } | |
| def kompose[A, B, C, F[_]](f: A => F[B])(g: B => F[C])(implicit let: Let[F]): A => F[C] = { a => | |
| let.let(f(a)) { b => | |
| let.let(g(b)) { c => | |
| let.pull(c) | |
| } | |
| } | |
| } | |
| // We captured the "notion of binding" in an anstraction named Let. | |
| // Let -> Monad | |
| // let -> bind, flatMap, (>>=) | |
| // pull -> point, pure | |
| // kompose -> Kleisli composition | |
| // WAIT!!! | |
| // Let has special syntax in almost every language, because it's so common. | |
| // Monadic bind has special syntax in FP languages, because it's fucking common. | |
| for { | |
| x <- mappa1.get(2) | |
| y <- mappa1.get(x.length) | |
| } yield x.concat(y) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment