Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Modular approach to abstractions from Category Theory
import Wizard.ConstUnit
import Wizard.Id
import scala.language.higherKinds
/*
Are there any constructions in Category Theory something like:
Given:
C category
F, G : functors in C
M functor category of category C
P morphism that map product of any two objects a and b from Category C into object a in M
*/
object Wizard {
type Id[A] = A // identity functor - what is it in functor category
type ConstUnit[A] = Unit // terminal object in functor category
type Void[A] = Nothing // initial object in functor category
}
trait Wizard[F[_], G[_]] {
type Spell[_[_], _[_], _, _] // transform 2 type constructors and 2 regular types into sth
def doMagic[A, B](f: Spell[F, G, A, B]): F[A] => G[B]
}
// F F A => B Functor
// F F A => F[B] FlatMap
// F F F[A] => B CoflatMap
// F F F[(A, B)] Zip
// F F F[A \/ B] Alt
// F F F[A => B] Ap (Apply)
// F F F[B => A] Divide
// ConstUnit F B Pointed (Pure, Applicative)
// ConstUnit Id F[B] CoPointed (CoApplicative)
trait Functor[F[_]] extends Wizard[F, F] {
type Spell[FF[_], GG[_], AA, BB] = AA => BB
// map(fa)(identity) == fa
// map(map(fa)(f))(g) == map(fa)(f andThen g)
def map[A, B](fa: F[A])(f: A => B): F[B] = doMagic[A, B](f)(fa)
}
trait FlatMap[F[_]] extends Wizard[F, F] { // Monad
type Spell[FF[_], GG[_], AA, BB] = AA => FF[BB]
// flatMap(flatMap(fa)(f))(g) == flatMap(fa)(a => flatMap(f(a))(g))
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] = doMagic[A, B](f)(fa)
}
trait Zip[F[_]] extends Wizard[F, F] { // Apply
type Spell[FF[_], GG[_], AA, BB] = FF[(AA, BB)]
def tuple2[A,B](fa: F[A])(fab: F[(A,B)]): F[B] = doMagic[A,B](fab)(fa)
}
trait Alt[F[_]] extends Wizard[F, F] { // Alt
type Spell[FF[_], GG[_], AA, BB] = FF[Either[AA, BB]]
def either2[A, B](fa: F[A])(fab: F[Either[A, B]]): F[B] = doMagic[A,B](fab)(fa)
}
trait Ap[F[_]] extends Wizard[F, F] { // Apply
type Spell[FF[_], GG[_], AA, BB] = FF[AA => BB]
def ap[A, B](fa: F[A])(f: F[A => B]): F[B] = doMagic[A, B](f)(fa)
}
trait Pointed[F[_]] extends Wizard[ConstUnit, F] { // Applicative
type Spell[FF[_], GG[_], AA, BB] = BB
def pure[B](value: B): F[B] = doMagic(value)(())
}
trait CoFlatMap[F[_]] extends Wizard[F, F] {
type Spell[FF[_], GG[_], AA, BB] = FF[AA] => BB
def extend[A, B](fa: F[A])(f: F[A] => B): F[B] = doMagic[A, B](f)(fa)
}
trait CoPointed[F[_]] extends Wizard[ConstUnit, Id] { // CoApplicative
type Spell[FF[_], GG[_], AA, BB] = FF[BB]
def coPure[B](value: F[B]): B = doMagic(value)()
}
trait Contravariant[F[_]] extends Wizard[F, F] {
type Spell[FF[_], GG[_], AA, BB] = BB => AA
// contramap(fa)(identity) == fa
// contramap( contrampa(fa)(f) )(g) == contramap(fa)(f andThen g)
def contramap[A, B](fa: F[A])(f: B => A): F[B] = doMagic[A, B](f)(fa)
}
trait Divide[F[_]] extends Wizard[F, F] {
type Spell[FF[_], GG[_], AA, BB] = FF[BB => AA]
def contraAp[A, B](fa: F[A])(f: F[B => A]): F[B] = doMagic[A, B](f)(fa)
}
// TODO
//trait Foldable[F[_]] {
// def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B
//}
// TODO can we express duplicate and flatten somehow ?
// TODO what would happen with when combining different types of F like Id ConstUnit with F[A] => F[B]
// a lot of different ways to specify identity (if FF == F and GG == G)
// TODO Traversable, Distributive, MonadTrans do not fit this framework
// what it tells us about them ?
//trait Distributive[F[_], G[_]] extends Wizard[F[G[_]], F[G[_]]] {
// type Spell[FF[_], GG[_], AA, BB] = AA => F[BB]
// def distribute[G[_], A, B](ga: G[A])(f: A => F[B]): F[G[B]] TODO forall
//def distribute[A, B](ga: G[A])(f: A => F[B]): F[G[B]] = doMagic[A,B](f)(ga) :(
// def cosequence[G[_], A](ga: G[F[A]]): F[G[A]]
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.