Skip to content

Instantly share code, notes, and snippets.

@lamdor
Created October 11, 2011 23:46
Show Gist options
  • Save lamdor/1279817 to your computer and use it in GitHub Desktop.
Save lamdor/1279817 to your computer and use it in GitHub Desktop.
trait Functor[F[_]] {
def fmap[A,B](f: A => B): F[A] => F[B]
}
sealed trait Fruit
class Apple extends Fruit
class Orange extends Fruit
case class Basket[T](items: T*)
object BasketFunctor extends Functor[Basket] {
def fmap[T, B](f: T => B) =
(b: Basket[T]) => Basket(b.items.map(f): _*)
}
val apple = new Apple
val orange = new Orange
val basketOfApples = Basket(List(apple, apple))
val convertToOranges = BasketFunctor.fmap((a: Apple) => orange)
trait Pointed[F[_]] {
def point[A](a: => A): F[A]
}
object PointedBasket extends Pointed[Basket] {
def point[T](item: => T) = Basket(item)
}
val oneAppleInABasket = PointedBasket.point(apple)
trait PointedFunctor[F[_]] extends Functor[F] with Pointed[F] {
val functor: Functor[F]
val pointed: Pointed[F]
def point[A](a: => A): F[A] = pointed.point(a)
def fmap[A,B](f: A => B): F[A] => F[B] = functor.fmap(f)
}
object BasketPointedFunctor extends PointedFunctor[Basket] {
val functor = BasketFunctor
val pointed = PointedBasket
}
trait Applic[F[_]] {
def applic[A,B](f: F[A => B]): F[A] => F[B]
}
object BasketApplic extends Applic[Basket] {
def applic[A,B](f: Basket[A => B]) = { (b: Basket[A]) =>
val product: Seq[B] = b.items.flatMap(i => f.items.map(bf => bf(i)))
Basket(product: _*)
}
}
sealed trait Juice[F <: Fruit]
case class OrangeJuice extends Juice[Orange]
case class AppleJuice extends Juice[Apple]
val juicer = (f: Fruit) => f match {
case o: Orange => new OrangeJuice
case a: Apple => new AppleJuice
}
val xmasPresent = Basket(juicer, juicer)
val basketOfFruit: Basket[Fruit] = Basket(orange, apple, orange)
val juiceLikeJackLaLane = BasketApplic.applic(xmasPresent)
juiceLikeJackLaLane(basketOfFruit)
trait Applicative[F[_]] {
val pointedFunctor: PointedFunctor[F]
val applic: Applic[F]
def functor: Functor[F] = new Functor[F] {
def fmap[A, B](f: A => B) = pointedFunctor fmap f
}
def pointed: Pointed[F] = new Pointed[F] {
def point[A](a: => A) = pointedFunctor point a
}
def fmap[A, B](f: A => B): F[A] => F[B] = functor.fmap(f)
def point[A](a: => A): F[A] = pointed.point(a)
def apply[A, B](f: F[A => B]): F[A] => F[B] = applic.applic(f)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment