Skip to content

Instantly share code, notes, and snippets.

@justinhj
Created July 9, 2019 19:08
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/64b94c29c509097fb5b17b3405f6bd97 to your computer and use it in GitHub Desktop.
Save justinhj/64b94c29c509097fb5b17b3405f6bd97 to your computer and use it in GitHub Desktop.
Flatmap from unit and compose
object ComposePlay {
// Compose takes two Kleisli arrows ( A => F[B], B => F[C] ) and returns A => F[C]
// Here I implement unit and compose for Option
// Then flatMap is implemented using compose showing that you can make a Monad
// with unit and compose...
def unitOption[A](a : A) : Option[A] = Some(a)
// The core work to be done by compose is must extract the B from the F[B] that the f
// produces so that g can be applied
def composeOption[A,B,C](f: A => Option[B], g: B => Option[C]): A => Option[C] = { a =>
val fb = f(a)
fb match {
case Some(b) => g(b)
case None => None
}
}
// The tricky part here is that flatMap takes an F[A] but compose needs an A
// so composeOption's first argument passes the fa and returns it
// This way the second function gets the F[A] to work with and as you can
// see in the composeOption code, the b is extracted from the F[B] and then
// we're good to go
def flatMapOption[A,B](fa : Option[A])(f: A => Option[B]) = {
composeOption((fa : Option[A]) => fa, (a : A) => f(a))(fa)
}
// A slightly neater version that calls out that the first function is the identity
def flatMapOption2[A,B](fa : Option[A])(f: A => Option[B]) = {
composeOption[Option[A],A,B](identity, (a : A) => f(a))(fa)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment