Skip to content

Instantly share code, notes, and snippets.

@retronym
Created December 11, 2011 07:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save retronym/1458981 to your computer and use it in GitHub Desktop.
Save retronym/1458981 to your computer and use it in GitHub Desktop.
Type Classes using type members, rather than type parameters
trait Semigroup_ {
type F
def append(a: F, b: => F): F
}
trait Monoid_ extends Semigroup_ {
def zero: F
}
trait Functor_ {
self =>
type F[_]
def map[A, B](fa: F[A])(f: A => B): F[B]
def compose(G: Functor_) = new Functor_ {
type F[a] = self.F[G.F[a]]
def map[A, B](fa: F[A])(f: A => B): F[B] = self.map(fa)(G.map(_)(f))
}
}
trait Pointed_ extends Functor_ {
def point[A](a: => A): F[A]
}
trait Bind_ extends Functor_ {
def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
}
trait Monad_ extends Pointed_ with Bind_ {
def map[A, B](fa: F[A])(f: A => B): F[B] = bind(fa)(a => point(f(a)))
}
sealed abstract trait Ordering
object Ordering {
case object LT extends Ordering
case object EQ extends Ordering
case object GT extends Ordering
implicit object OrderingMonoid extends Monoid_ {
type F = Ordering
def zero = EQ
def append(a: F, b: => F): F = a match {
case EQ => b
case x => x
}
}
}
case class Identity[A](value: A)
object Identity {
implicit object IdentityMonad extends Monad_ {
type F[A] = Identity[A]
def point[A](a: => A): F[A] = Identity(a)
def bind[A, B](a: F[A])(f: A => F[B]) = f(a.value)
}
}
case class State[S, A](run: S => (A, S))
object State {
implicit def StateMonad[S] = new Monad_ {
type F[a]=State[S, a]
def point[A](a: => A): F[A] = State(s => (a, s))
def bind[A, B](fa: F[A])(f: A => F[B]): F[B] = State{ s =>
val (a, s1) = fa.run(s)
f(a).run(s1)
}
}
}
object Alias {
type Semigroup[G] = Semigroup_ { type F = G }
type Monoid[G] = Monoid_ { type F = G }
type Functor[G[_]] = Functor_ { type F[A] = G[A] }
type Pointed[G[_]] = Pointed_ { type F[A] = G[A] }
type Bind[G[_]] = Bind_ { type F[A] = G[A] }
type Monad[G[_]] = Monad_ { type F[A] = G[A] }
def ?[A <: AnyRef](implicit a: A): a.type = a
}
object Test {
import Alias._
// Need the imports here, unfortunately, as the parts of a type don't include the
// RHS of type members, it only includes the type arguments.
import Ordering._
import Identity._
?[Monad[Identity]]
?[Semigroup[Ordering]]
// No need to explicitly annotate the type arguments to compose,
// as would be needed of it accepted a Functor[F[_]]
?[Functor[Identity]].compose(State.StateMonad[Int])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment