Created
December 11, 2011 07:02
-
-
Save retronym/1458981 to your computer and use it in GitHub Desktop.
Type Classes using type members, rather than type parameters
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
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