Skip to content

Instantly share code, notes, and snippets.

@fsarradin
Created December 9, 2014 15:18
Show Gist options
  • Save fsarradin/5806bc6324f44161304e to your computer and use it in GitHub Desktop.
Save fsarradin/5806bc6324f44161304e to your computer and use it in GitHub Desktop.
Reader functor in Scala (the typeclass way)
object FunctorModule {
trait Functor[F[_]] {
def map[A, B](f: A => B): F[A] => F[B]
}
implicit class ReaderFunctor[E](r: E => _) extends Functor[({ type l[a] = E => a })#l] {
override def map[A, B](f: A => B): (E => A) => (E => B) = { r => r andThen f }
}
implicit def functorOps[F[_]: Functor, A](fa: F[A]) = new {
val functor = implicitly[Functor[F]]
final def map[B](f: A => B): F[B] = functor.map(f)(fa)
}
def main(args: Array[String]) {
val f: (Int) => Int = (_: Int) * 5
val g: (Int) => Int = (_: Int) + 3
// what a type!?
val h: ((Int) => Int) => (Int) => Int = f map g
// compilation error here because 8 of type Int doesn't match (Int) => Int
println(h(8))
}
}
@massyl
Copy link

massyl commented Dec 12, 2014

The whole solution 😄

import scala.language.higherKinds;
import scala.language.implicitConversions;
import scala.language.reflectiveCalls;
import scala.Predef;

object FunctorModule {

  trait Monad[M[_]] {
    def point[A](a: A): M[A]
    def bind[A, B](ma: M[A], f: A => M[B]): M[B]
  }

  trait Functor[F[_]] {
    def fmap[A, B](f: A => B)(fa: F[A]): F[B]
  }

  case class Reader[-E, +A](runReader: E => A) {
    def apply(e: E) = runReader(e)
    def map[B](f: A => B): Reader[E, B] = Reader(runReader andThen f)
  }

  implicit def FunctorReader[E] = new Functor[({ type T[A] = Reader[E, A] })#T] {
    override def fmap[A, B](f: A => B)(fa: Reader[E, A]): Reader[E, B] = fa map f
  }

  implicit def MonadReader[E] = new Monad[({ type T[A] = Reader[E, A] })#T] {
    def point[A](a: A): Reader[E, A] = Reader(_ => a)
    def bind[A, B](ma: Reader[E, A], f: A => Reader[E, B]): Reader[E, B] = Reader(e => f(ma(e))(e))
  }

  implicit def arrawToF[E, A](fa: E => A) = new {
    val F = implicitly[Functor[({ type T[A] = Reader[E, A] })#T]]
    def fmap[B](f: A => B): Reader[E, B] = F.fmap(f)(Reader(fa))
  }

  implicit def arrawToM[E, A, B](continuation: A => B) = new {
    val M = implicitly[Monad[({ type T[A] = Reader[E, A] })#T]]
    def bind(ma:Reader[E, A]):Reader[E, B] = M.bind(ma, (a : A) => M.point(continuation(a)))
  }

  def main(args: Array[String]) {
    val f = (_: Int) * 5
    val g = (_: Int) + 3
    val h: Reader[Int, Int] = f fmap g
    println(h(8))
    println(f.bind(h)(8))

   //Monad laws validation
    //1) Left identity : return >>= fa = fa
    val result : Int = h.runReader.bind(Reader((a : Int) => a))(3)
    assert(result == h(3))

    //2) Right  Identity : fa >>= return = fa
    val result2 : Int =((a : Int) => a).bind(h)(3)
    assert(result2 == h(3))

    //3) Associativity (f >>= g) >>= h = f >>= (\a -> g a >>= h)
    val ma = h
    val mc = (_: Int) + 9
    val mb = ((a: Int) => a * 10)

    //(ma >>= mb)>>= mc
    val assocResult = mc.bind(mb.bind(ma))(3)
   //(ma >>= (\a => mb(a) >>= mc)
    val assocResult2 = (mc.bind(Reader((a: Int) => mb(a))).runReader).bind(ma)(3)

    assert(assocResult == assocResult2)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment