Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@mandubian
Last active September 30, 2019 21:39
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mandubian/dfd670f7740f47a1a2a7b662f828aac6 to your computer and use it in GitHub Desktop.
Save mandubian/dfd670f7740f47a1a2a7b662f828aac6 to your computer and use it in GitHub Desktop.
"Monad is a monoid in the category of endofunctors" evidence using trivial sample of Scala Kind-Polymorphism PoC
/** Showing with Kind-Polymorphism the evidence that Monad is a monoid in the category of endofunctors */
object Test extends App {
/** Monoid (https://en.wikipedia.org/wiki/Monoid_(category_theory))
* In category theory, a monoid (or monoid object) (M, μ, η) in a monoidal category (C, ⊗, I)
* is an object M together with two morphisms
*
* μ: M ⊗ M → M called multiplication,
* η: I → M called unit
*
*/
trait Monoid[M <: AnyKind, →[_<:AnyKind, _<:AnyKind], ⊗ <: AnyKind, I <: AnyKind] {
def η: →[I, M]
def μ: →[⊗, M]
@inline def unit = η
@inline def mult = μ
}
////////////////////////////////////////////////////////
// Monoid for monomorphic types
//
trait Monoid1[A] extends Monoid[A, Function1, Tuple2[A, A], Unit]
/** Sample with Int & integer multiplication */
object MonoidIntMul extends Monoid1[Int] {
val η: Unit => Int = _ => 1
val μ: ((Int, Int)) => Int = { case (a, b) => a * b }
}
////////////////////////////////////////////////////////
// Monads as monoids
// Definition: "Monad is a monoid in the category of endofunctor induced by the composition and the identity functor"
//
/** Classic functor */
trait Functor[M[_]] {
def map[A, B](f: A => B): M[A] => M[B]
}
/** Functor Morphism (aka Natural Transformation) */
trait ~>[F[_], G[_]] {
def apply[A](fa: F[A]): G[A]
}
/** Id functor */
type Id[A] = A
/** Functor Composition */
type Comp[F[_], G[_], A] = F[G[A]]
abstract class Monad[M[_]: Functor] extends Monoid[M, ~>, ({type l[t] = Comp[M, M, t] })#l, Id] {
// classic point/pure & flatMap/bind encoded using monoid & functor operations
def point[A](a: A): M[A] = unit(a)
def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B] = mult(implicitly[Functor[M]].map(f)(ma))
}
/** Sample with List */
implicit object FunctorList extends Functor[List] {
def map[A, B](f: A => B): List[A] => List[B] = l => l.map(f)
}
object MonadList extends Monad[List] {
val η: Id ~> List = new (Id ~> List) {
def apply[A](ida: Id[A]) = List()
}
val μ: ({type l[A] = List[List[A]] })#l ~> List = new (({type l[A] = List[List[A]] })#l ~> List) {
def apply[A](ls: List[List[A]]): List[A] = ls.flatten
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment