Created
September 1, 2016 23:29
-
-
Save calvinlfer/5e3c1c34cf66354a05e0da5d36c66c9a to your computer and use it in GitHub Desktop.
Implementing the Monad and Functor typeclass in Scala and also looking into Point Free
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
| import scala.language.higherKinds | |
| // Functor typeclass - it abstracts over higher kinded types (functions at the type level) | |
| trait Functor[HigherKindedType[_]] { | |
| def map[A, B](functorA: HigherKindedType[A])(mapper: A => B): HigherKindedType[B] | |
| def unit[A](simpleA: => A): HigherKindedType[A] | |
| } | |
| // Monad typeclass - it also abstracts over higher kinded types (functions at the type level) | |
| // A Monad is also a Functor | |
| trait Monad[HigherKindedType[_]] extends Functor[HigherKindedType] { | |
| def flatMap[A, B](monadA: HigherKindedType[A])(nestedMapper: A => HigherKindedType[B]): HigherKindedType[B] | |
| // if you implement flatMap, then you get map for free :-) | |
| def map[A, B](monadA: HigherKindedType[A])(mapper: A => B): HigherKindedType[B] = | |
| flatMap(monadA)(a => unit(mapper(a))) | |
| } | |
| // Monad typeclass implementation for List (List is a higher kinded type) | |
| implicit val listMonad = new Monad[List] { | |
| override def flatMap[A, B](monadA: List[A])(nestedMapper: (A) => List[B]): List[B] = monadA.flatMap(nestedMapper) | |
| override def unit[A](simpleA: => A): List[A] = List(simpleA) | |
| } | |
| // Point free symbolic flatMap and curried so you can easily compose | |
| def >>=[A, B, HigherKindedType[_]](nestedMapper: A => HigherKindedType[B]) | |
| (higherKindTypeOfA: HigherKindedType[A]) | |
| (implicit monadTypeClassImplementation: Monad[HigherKindedType]): HigherKindedType[B] = { | |
| monadTypeClassImplementation.flatMap(higherKindTypeOfA)(nestedMapper) | |
| } | |
| // Point free | |
| def unit[A, HigherKindedType[_]](simpleA: => A)(implicit monadTypeClassImplementation: Monad[HigherKindedType]) = | |
| monadTypeClassImplementation.unit(simpleA) | |
| // partially apply both >>= and unit using the point free style | |
| // (>>=[Int, Int, List]((x: Int) => List(x + 1)) _) means we feed in the first argument (nestedMapper of type Int => List[Int]) | |
| // and leave higherKindedTypeOfA to be filled in later, hence the underscore _ (higherKindedTypeOfA is a List[A] in this case) | |
| // (unit[Int, List] _) means we leave the argument to be filled in later (simpleA is of type lazily evaluated Int which means => Int) | |
| // its argument is a lazily evaluated int (treat it as Int) and it produces a List[Int] | |
| // reads right to left like mathematical composition | |
| val composedFunction: (=> Int) => List[Int] = | |
| (>>=[Int, Int, List]((x: Int) => List(x + 1)) _) compose (unit[Int, List] _) | |
| composedFunction(10) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment