Skip to content

Instantly share code, notes, and snippets.

@fsarradin
Created December 9, 2014 15:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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))
}
}
@joune
Copy link

joune commented Dec 9, 2014

functorOps is not used here: function f is simply lifted to a ReaderFunctor, which explains the type of "f map g"

@massyl
Copy link

massyl commented Dec 10, 2014

Et voilouououou :-)

package test
import scala.language.higherKinds;
import scala.language.implicitConversions;
import scala.language.reflectiveCalls;

object FunctorModule {

  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((e: E) => f(runReader(e)))

  }

  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 functorOps[E, A](fa: E => A) = new {
    def fmap[B](f: A => B): Reader[E, B] = FunctorReader.fmap(f)(Reader(fa))
  }

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

@massyl
Copy link

massyl commented Dec 10, 2014

I think that we can do better, i didn't bother myself on the best way to do it. My aim is just to make your code working. The best way is to follow patterns that scalaz uses.

@fsarradin
Copy link
Author

Knowing that if I add the code below, it doesn't seem to work anymore...

case class Id[A](a: A)

def mapId[A, B](f: A => B, i: Id[A]): Id[B] = Id(f(i.a))

implicit def IdFunctor = new Functor[Id] {
  def map[A, B](f: A => B) = {
    functor: Id[A] => mapId(f, functor)
  }
}

Meaning that, in this case, functorOps doesn't fulfill its initial role to add the map method to the existing functor.

@massyl
Copy link

massyl commented Dec 11, 2014

Second version using point free style 😄

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

object FunctorModule {

  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 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))
  }

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

@massyl
Copy link

massyl commented Dec 11, 2014

arrawToF works on

 E => A 

type

@massyl
Copy link

massyl commented Dec 11, 2014

One more exercice for you 😄
Make the Reader class given before as instance of Monad given bellow and prove 3 Laws :

  1. Left identity : return a >>= f = f a
  2. Right Identity : ma >>= return = ma
  3. Associativity : (f >>= g) >>= h == f >>= ((\a -> g a) >>= h)
trait Monad[M[_]] {                                                                                              
   def point[A](a: A): M[A]                                                                                       
   def bind[A, B](ma: M[A], f: A => M[B]): M[B]                                                                   
 }  

@fsarradin
Copy link
Author

"Et voilà !"

  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)

    def bind[B](f: A => Reader[E, B]): Reader[E, B] =
      Reader { e: E =>
        val a: A = runReader(e)
        f(a).runReader(e)
      }
  }

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

@massyl
Copy link

massyl commented Dec 12, 2014

you can do

Reader { e: E =>f(runReader(e))(e) }

@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