Created
October 2, 2014 23:58
-
-
Save jcoveney/4e609e6318a5f8037bda to your computer and use it in GitHub Desktop.
Endofunctor attempt
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
// The following are just some useful category theoretic type classes | |
// Note that this IS an endofunctor -- it has to be. Our category is all possible types, | |
// so the type A and T[A] are both in our Category, so it's an endofunctor | |
trait Functor[T[_]] { | |
def map[A, B](fn: A => B): T[A] => T[B] | |
} | |
trait Monad[T[_]] extends Functor[T] { | |
// we go with the less common join approach because THIS is where the "monoid"-ness of | |
// the Monad comes in. Because we take T[T[A]] => T[A], which if you wave your hands | |
// is like T . T => T, which looks Monoid-y | |
def join[A](t: T[T[A]]): T[A] | |
def unit[A](a: A): T[A] | |
// We implement this to show that a Monad is flatMap/unit, or join/map/unit | |
def flatMap[A, B](fn: A => T[B]): T[A] => T[B] = { a: T[A] => join(map(fn)(a)) } | |
} | |
trait Monoid[T] { | |
def plus(left: T, right: T): T | |
def zero: T | |
} | |
// We could just use the monad, but to make it explicit we have this split out | |
implicit val listFunctor: Functor[List] = new Functor[List] { | |
override def map[A, B](fn: A => B): List[A] => List[B] = { a: List[A] => a.map(fn) } | |
} | |
implicit val listMonad: Monad[List] = new Monad[List] { | |
override def join[A](t: List[List[A]]): List[A] = t.flatten | |
override def unit[A](a: A): List[A] = List(a) | |
override def map[A, B](fn: A => B): List[A] => List[B] = listFunctor.map(fn) | |
} | |
implicit def monadIsAMonoid[T[_]](implicit m: Monad[T]): Monoid[Functor[T]] = new Monoid[Functor[T]] { | |
override def plus(left: Functor[T], right: Functor[T]): Functor[T] = new Functor[T] { | |
override def map[A, B](fn: A => B): T[A] => T[B] = { a: T[A] => | |
// This looks a little weird, but if you squint at it, it's just calling join, the structural "plus" of the monad, | |
// on the right and left mapped together | |
m.join(right.map(left.map(fn))(m.unit(a))) | |
} | |
} | |
// This is actually useful because it gets at the heart of what we are composing. We are composing the "functor"-iness | |
// of a monad | |
override def zero: Functor[T] = new Functor[T] { | |
override def map[A, B](fn: A => B): T[A] => T[B] = m.map(fn) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment