Last active
March 1, 2017 22:20
-
-
Save justinhj/482f1e92b1fed424a94d48e5d972fe47 to your computer and use it in GitHub Desktop.
Functors Monads and Applicatives scala worksheet
This file contains 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
import scalaz.{Applicative, Functor, Monad} | |
// Based on https://thedet.wordpress.com/2012/04/28/functors-monads-applicatives-can-be-so-simple/ | |
object FMA { | |
// A simple effectful type constructor | |
// All it does is wrap a value of any type | |
case class MyBox[T](val value:T) | |
// sample use | |
val s1 = MyBox("Hello world") | |
// Let's say we have length function for string | |
def sLen(s: String) = s.size | |
val ss1 = sLen("Hello World") | |
// a) ( A=>B ) => ( C[A]=>C[B] ) | Functor | |
// but cannot apply to the one in the Box :( | |
// so we need map (provided by Functor) | |
val f1 = new Functor[MyBox] { | |
def map[A, B](fa: MyBox[A])(f: A => B): MyBox[B] = { | |
MyBox(f(fa.value)) | |
} | |
} | |
// Now we can use our sLen function | |
val f1m = f1.map(s1){sLen} | |
// So we unwrap A, applied f to get a B and wrapped it again | |
// Next problem, we have a function that takes an A and a mapping from | |
// A to B but returns the wrapped version of A | |
// b) ( A=>C[B] ) => ( C[A]=>C[B] ) | Monad | |
def sLenToBox(s: String): MyBox[Int] = { | |
MyBox(s.size) | |
} | |
// So we need a monad | |
val m1 = new Monad[MyBox] { | |
// we need to know how to wrap an A | |
def point[A](a: => A): MyBox[A] = MyBox(a) | |
// Recognize flatMap? It's bind! | |
// def flatMap[A, B](l: MyBox[A])(f: A => MyBox[B]): MyBox[B] | |
def bind[A, B](fa: MyBox[A])(f: A => MyBox[B]): MyBox[B] = { | |
f(fa.value) | |
} | |
} | |
// Now we can use our function | |
val m11 = m1.bind(s1)(sLenToBox) | |
// Last problem | |
// c) ( C[A=>B] ) => ( C[A]=>C[B] ) | Applicative | |
// We have a function that is itself in the box | |
val boxedLen = MyBox[String => Int](s => sLen(s)) | |
// To use it we need Applicative apply function | |
// def apply[A,B](b:MyBox[A=>B]): MyBox[A]=>MyBox[B] = (a:MyBox[A]) => new MyBox(b.value(a.value)) | |
val a1 = new Applicative[MyBox] { | |
def point[A](a: => A) = MyBox(a) | |
// We know how to unwrap A and how to wrap a B so we do that | |
// but also we need to unwrap the function itself | |
def ap[A,B](fa: => MyBox[A])(f: => MyBox[A => B]): MyBox[B] = { | |
MyBox(f.value(fa.value)) | |
} | |
} | |
// let's apply it | |
val a1a = a1.ap(s1)(boxedLen) | |
// Note that we only needed the applicative function, we didn't need to | |
// make an applicative. Why? Because Monad implements applicative! | |
val monadAp = m1.ap(s1)(boxedLen) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment