Skip to content

Instantly share code, notes, and snippets.

@esarbe
Last active November 20, 2015 16:06
Show Gist options
  • Save esarbe/d4e50bb7c6c0d3b1c5f6 to your computer and use it in GitHub Desktop.
Save esarbe/d4e50bb7c6c0d3b1c5f6 to your computer and use it in GitHub Desktop.
object FunctorComposition extends App {
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
sealed trait Maybe[+T]
case class Some[T](value: T) extends Maybe[T]
case object None extends Maybe[Nothing]
object Maybe {
def apply[T](item: T): Maybe[T] = item match {
case null => None
case _ => Some(item)
}
}
sealed trait List[+A] {
def ::[B >: A](item: B): List[B] = Cons(item, this)
}
case class Cons[T](value: T, next: List[T] = Empty) extends List[T]
case object Empty extends List[Nothing]
implicit object MaybeFunctor extends Functor[Maybe] {
def create[A](a: A): Maybe[A] = Some(a)
def map[A, B](fa: Maybe[A])(f: A => B): Maybe[B] = fa match {
case Some(value) => Some(f(value))
case None => None
}
}
implicit object ListFunctor extends Functor[List] {
def create[A](a: A): List[A] = Cons(a)
def map[A, B](fa: List[A])(f: (A) => B): List[B] = fa match {
case Cons(elem, next) => Cons(f(elem), this.map(next)(f))
case Empty => Empty
}
}
implicit class FunctorSyntax[F[_], +A](self: F[A])(implicit F: Functor[F]) {
def map[B](f: A => B): F[B] = F.map(self)(f)
}
var list = 1 :: 2 :: 3 :: Empty
list.map( _ + 1)
val id = ListFunctor.map(list)(x => x) // works
val mList = list.map( _ + 1) // works with type coersion
val maybePlusOne = Maybe(1).map(_ + 1) // don't compile
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment