Created
December 9, 2014 15:18
-
-
Save fsarradin/5806bc6324f44161304e to your computer and use it in GitHub Desktop.
Reader functor in Scala (the typeclass way)
This file contains hidden or 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
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)) | |
} | |
} |
"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
}
you can do
Reader { e: E =>f(runReader(e))(e) }
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
One more exercice for you 😄
Make the Reader class given before as instance of Monad given bellow and prove 3 Laws :
return a >>= f = f a
ma >>= return = ma
(f >>= g) >>= h == f >>= ((\a -> g a) >>= h)