Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save calvinlfer/5e3c1c34cf66354a05e0da5d36c66c9a to your computer and use it in GitHub Desktop.

Select an option

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
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