Created
June 9, 2016 13:36
-
-
Save takeouchida/be226a17f4b47f9b04a30bf263fbebee to your computer and use it in GitHub Desktop.
A rough implementation of some type classes in Scala
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
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