Skip to content

Instantly share code, notes, and snippets.

@takeouchida
Created June 9, 2016 13:36
Show Gist options
  • Save takeouchida/be226a17f4b47f9b04a30bf263fbebee to your computer and use it in GitHub Desktop.
Save takeouchida/be226a17f4b47f9b04a30bf263fbebee to your computer and use it in GitHub Desktop.
A rough implementation of some type classes in Scala
package object typeclasses {
trait Functor[F[_]] { self =>
def fmap[A, B](fa: F[A])(f: A => B): F[B]
}
trait Applicative[F[_]] extends Functor[F] { self =>
def pure[A](a: => A): F[A]
def ap[A, B](fa: F[A])(f: F[A => B]): F[B]
}
trait Monad[F[_]] extends Applicative[F] { self =>
def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
}
trait ListInstances {
implicit val listInstance: Monad[List] = new Monad[List] {
override def fmap[A, B](l: List[A])(f: (A) => B): List[B] = l.map(f)
override def pure[A](a: => A): List[A] = a :: Nil
override def ap[A, B](fa: List[A])(f: List[(A) => B]): List[B] = fa.flatMap(a => f.map(g => g(a)))
override def bind[A, B](fa: List[A])(f: (A) => List[B]): List[B] = fa.flatMap(f)
}
}
trait OptionInstances {
implicit val optionInstance: Monad[Option] = new Monad[Option] {
override def fmap[A, B](fa: Option[A])(f: (A) => B): Option[B] = fa.map(f)
override def ap[A, B](fa: Option[A])(f: Option[(A) => B]): Option[B] = f match {
case None => None
case Some(g) => fa match {
case None => None
case Some(x) => Some(g(x))
}
}
override def pure[A](a: => A): Option[A] = Some(a)
override def bind[A, B](fa: Option[A])(f: (A) => Option[B]): Option[B] = fa.flatMap(f)
}
}
final class FunctorOps[F[_], A](val self: F[A])(implicit val F: Functor[F]) {
def fmap[B](f: A => B): F[B] = F.fmap(self)(f)
}
final class ApplicativeOps[F[_], A](val self: F[A])(implicit val F: Applicative[F]) {
def <*>[B](f: F[A => B]): F[B] = F.ap(self)(f)
}
final class MonadOps[F[_], A](val self: F[A])(implicit val F: Monad[F]) {
def >>=[B](f: A => F[B]) = F.bind(self)(f)
}
trait ToFunctorOps {
implicit def ToFunctorOps[F[_], A](v: F[A])(implicit F0: Functor[F]) = new FunctorOps[F, A](v)
}
trait ToApplicativeOps extends ToFunctorOps {
implicit def ToApplicativeOps[F[_], A](v: F[A])(implicit F0: Applicative[F]) = new ApplicativeOps[F, A](v)
}
trait ToMonadOps extends ToApplicativeOps {
implicit def ToMonadOps[F[_], A](v: F[A])(implicit F0: Monad[F]) = new MonadOps[F, A](v)
}
trait AllInstances extends ListInstances with OptionInstances
trait ToTypeClassOps extends ToMonadOps
object TypeClasses extends AllInstances with ToTypeClassOps
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment