Last active
December 23, 2015 04:18
-
-
Save tonymorris/6578904 to your computer and use it in GitHub Desktop.
Scala type-class hierarchy
This file contains 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 annotation._ | |
case class Pronunciation(pronounce: String) extends StaticAnnotation | |
case class Law(name: String, denotation: String) extends StaticAnnotation | |
trait ~>[F[_], G[_]] { | |
def apply[A]: F[A] => G[A] | |
} | |
case class Id[A](x: A) | |
trait Equal[A] { | |
def equal: A => A => Boolean | |
} | |
sealed trait Ordering | |
case object LT extends Ordering | |
case object EQ extends Ordering | |
case object GT extends Ordering | |
trait Order[A] extends Equal[A] { | |
def order: A => A => Ordering | |
} | |
trait Semigroup[M] { | |
def op: M => M => M | |
} | |
trait Monoid[M] extends Semigroup[M] { | |
val id: M | |
} | |
trait Functor[F[_]] { | |
@Pronunciation(pronounce = "eff-map") | |
def fmap[A, B](f: A => B): F[A] => F[B] | |
@Law(name = "Identity", denotation = "∀x. fmap (λq.q) x = x") | |
def identity[A](x: F[A])(implicit E: Equal[F[A]]): Boolean = | |
E.equal(fmap[A, A](q => q)(x))(x) | |
@Law(name = "Composition", denotation = "∀f.∀g.∀x. fmap f (fmap g x) = fmap (f∘g) x") | |
def composition[A, B, C](f: B => C, g: A => B, x: F[A])(implicit E: Equal[F[C]]): Boolean = | |
E.equal(fmap(f)(fmap(g)(x)))(fmap(f compose g)(x)) | |
} | |
trait Profunctor[=>:[_, _]] { | |
def mapfst[A, B, C](f: C => A): (A =>: B) => (C =>: B) | |
def mapsnd[A, B, C](f: B => C): (A =>: B) => (A =>: C) | |
} | |
trait Apply[F[_]] extends Functor[F] { | |
def ap[A, B](f: F[A => B]): F[A] => F[B] | |
} | |
trait Bind[F[_]] extends Apply[F] { | |
def bind[A, B](f: A => F[B]): F[A] => F[B] | |
} | |
trait Applicative[F[_]] extends Apply[F] { | |
def insert[A]: A => F[A] | |
} | |
trait Monad[F[_]] extends Applicative[F] with Bind[F] | |
trait Extend[F[_]] extends Functor[F] { | |
def extend[A, B](f: F[A] => B): F[A] => F[B] | |
} | |
trait Comonad[F[_]] extends Extend[F] { | |
def extract[A]: F[A] => A | |
} | |
trait ComonadApply[F[_]] extends Comonad[F] with Apply[F] | |
trait Plus[F[_]] extends Apply[F] { | |
def plus[A]: F[A] => F[A] => F[A] | |
} | |
trait Alternative[F[_]] extends Plus[F] with Applicative[F] { | |
def empty[A]: F[A] | |
} | |
trait BindPlus[F[_]] extends Plus[F] with Bind[F] | |
trait MonadPlus[F[_]] extends BindPlus[F] with Alternative[F] with Monad[F] | |
trait Contravariant[F[_]] { | |
def contramap[A, B](f: B => A): F[A] => F[B] | |
} | |
trait Distributive[T[_]] extends Functor[T] { | |
def distribute[F[_]: Functor, A, B](f: A => T[B]): F[A] => T[F[B]] | |
} | |
trait Fold[T[_]] { | |
def foldMap[A, M: Monoid](f: A => M): T[A] => M | |
} | |
trait Fold1[T[_]] extends Fold[T] { | |
def foldMap1[A, M: Semigroup](f: A => M): T[A] => M | |
} | |
trait Traverse[T[_]] extends Functor[T] with Fold[T] { | |
def traverse[F[_]: Applicative, A, B](f: A => F[B]): T[A] => F[T[B]] | |
} | |
trait Traverse1[T[_]] extends Traverse[T] with Fold1[T] { | |
def traverse1[F[_]: Apply, A, B](f: A => F[B]): T[A] => F[T[B]] | |
} | |
trait MonadTransformer[T[_[_], _]] { | |
def lift[M[_]: Monad, A]: M[A] => T[M, A] | |
} | |
trait BindTransformer[T[_[_], _]] extends MonadTransformer[T] { | |
def liftB[M[_]: Bind, A]: M[A] => T[M, A] | |
} | |
trait MonadTransform[T[_[_], _]] { | |
def transform[F[_]: Monad, G[_]: Monad, A](f: F ~> G): T[F, A] => T[G, A] | |
} | |
trait BindTransform[T[_[_], _]] extends MonadTransform[T] { | |
def transformB[F[_]: Bind, G[_]: Monad, A](f: F ~> G): T[F, A] => T[G, A] | |
} | |
trait ComonadTransformer[T[_[_], _]] { | |
def lower[M[_]: Comonad, A]: T[M, A] => M[A] | |
} | |
trait ExtendTransformer[T[_[_], _]] extends ComonadTransformer[T] { | |
def lowerE[M[_]: Extend, A]: T[M, A] => M[A] | |
} | |
trait ComonadHoist[T[_[_], _]] { | |
def cohoist[M[_]: Comonad, A]: T[M, A] => T[Id, A] | |
} | |
trait ExtendHoist[T[_[_], _]] extends ComonadHoist[T] { | |
def cohoistE[M[_]: Extend, A]: T[M, A] => T[Id, A] | |
} | |
trait Semigroupoid[~>[_, _]] { | |
def compose[A, B, C]: (B ~> C) => (A ~> B) => (A ~> C) | |
} | |
trait Category[~>[_, _]] extends Semigroupoid[~>] { | |
def id[A]: A ~> A | |
} | |
trait First[~>[_, _]] extends Semigroupoid[~>] { | |
def first[A, B, C]: (A ~> B) => ((A, C) ~> (B, C)) | |
} | |
trait Arrow[~>[_, _]] extends Category[~>] with First[~>] { | |
def idA[A, B]: (A => B) => (A ~> B) | |
} |
import scala.reflect.runtime.{universe => ru}
import scala.reflect.{internal => ri}
import scala.reflect.{api => ra}
val m = ru.runtimeMirror(getClass.getClassLoader)
val excludes = List("java.lang.Object","scala.Any","scala.AnyRef")
def parents[T:ru.TypeTag] =
ru.typeOf[T].asInstanceOf[ri.Types#Type].parents map { _.typeSymbol.fullName } filterNot {excludes.contains _}
insert
on Applicative
: What, pure / point / return isn't called enough things, already?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
scala> ofClass[Monad[List]]
res10: reflect.runtime.universe.ClassSymbol = trait Monad
scala> parents(res10)
res11: List[reflect.runtime.universe.ClassSymbol] = List(trait Bind, trait Applicative, trait Apply, trait Functor)
But I just want Applicative and Bind.