Skip to content

Instantly share code, notes, and snippets.

@justinhj
Last active March 1, 2017 22:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinhj/482f1e92b1fed424a94d48e5d972fe47 to your computer and use it in GitHub Desktop.
Save justinhj/482f1e92b1fed424a94d48e5d972fe47 to your computer and use it in GitHub Desktop.
Functors Monads and Applicatives scala worksheet
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