Skip to content

Instantly share code, notes, and snippets.

@tonymorris
Last active December 23, 2015 04:18
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tonymorris/6578904 to your computer and use it in GitHub Desktop.
Save tonymorris/6578904 to your computer and use it in GitHub Desktop.
Scala type-class hierarchy
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)
}
@pedrofurla
Copy link

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.

@pedrofurla
Copy link

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

@LeifW
Copy link

LeifW commented Sep 26, 2013

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