Last active
November 10, 2021 01:59
-
-
Save lombardo-chcg/21c275eb48647be97ee2a0c7685e34da to your computer and use it in GitHub Desktop.
functor hierarchy
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
| import scala.language.higherKinds | |
| object Example { | |
| // demo version of the Option type for example use | |
| sealed trait Maybe[+A] | |
| case class Just[+A](value: A) extends Maybe[A] | |
| case object Niente extends Maybe[Nothing] | |
| trait Functor[F[A]] { | |
| // fmap :: (a -> b) -> f a -> f b | |
| def fmap[A, B](f: A => B)(that: F[A]): F[B] | |
| // (<$) :: a -> f b -> f a | |
| def `<$`[A, B](a: A)(that: F[B]): F[A] | |
| } | |
| trait Applicative[F[A]] extends Functor[F] { | |
| // pure :: a -> f a | |
| def pure[A](a: A): F[A] | |
| // (<*>) :: f (a -> b) -> f a -> f b | |
| def <*>[A, B](f: F[A => B])(that: F[A]): F[B] | |
| } | |
| trait Monad[F[A]] extends Applicative[F] { | |
| // (>>=) :: m a -> (a -> m b) -> m b | |
| def >>=[A, B](a: F[A])(func: A => F[B]): F[B] | |
| } | |
| // Monad instance for our custom Maybe type | |
| implicit val maybeInstance: Monad[Maybe] = new Monad[Maybe] { | |
| // Functor methods | |
| def fmap[A, B](f: A => B)(that: Maybe[A]): Maybe[B] = | |
| that match { | |
| case Just(value) => Just(f(value)) | |
| case Niente => Niente | |
| } | |
| def `<$`[A, B](a: A)(that: Maybe[B]): Maybe[A] = | |
| that match { | |
| case Just(_) => Just(a) | |
| case Niente => Niente | |
| } | |
| // Applicative methods | |
| def <*>[A, B](f: Maybe[A => B])(that: Maybe[A]): Maybe[B] = | |
| (f, that) match { | |
| case (Just(func), Just(value)) => Just(func(value)) | |
| case _ => Niente | |
| } | |
| def pure[A](a: A): Maybe[A] = `return`(a) | |
| // Monad methods | |
| def >>=[A, B](a: Maybe[A])(func: A => Maybe[B]): Maybe[B] = | |
| a match { | |
| case Just(value) => func(value) | |
| case Niente => Niente | |
| } | |
| def `return`[A](a: A): Maybe[A] = Just(a) | |
| } | |
| // extension api for functor methods | |
| implicit class FunctorSyntax[F[_]: Functor, A](v: F[A]) { | |
| val instance: Functor[F] = implicitly[Functor[F]] | |
| def fmap[B](f: A => B): F[B] = instance.fmap(f)(v) | |
| // needed for for-comp syntax | |
| def map[B](f: A => B): F[B] = fmap(f) | |
| def `<$>`[B](f: A => B): F[B] = instance.fmap(f)(v) | |
| def `<$`[B](b: B): F[B] = instance.`<$`(b)(v) | |
| } | |
| // extension api for functor methods | |
| implicit class ApplicativeSyntax[F[_]: Applicative, A, B](func: F[A => B]) { | |
| val instance: Applicative[F] = implicitly[Applicative[F]] | |
| def <*>(that: F[A]): F[B] = instance.<*>(func)(that) | |
| } | |
| // extension api for functor methods | |
| implicit class MonadSyntax[F[_]: Monad, A, B](a: F[A]) { | |
| val instance: Monad[F] = implicitly[Monad[F]] | |
| def >>=(func: A => F[B]): F[B] = instance.>>=(a)(func) | |
| // needed for for-comp syntax | |
| def flatMap(func: A => F[B]): F[B] = >>=(func) | |
| } | |
| def main(args: Array[String]): Unit = { | |
| val ex: Maybe[Int] = Just(10) | |
| val res1 = maybeInstance.fmap[Int, Int](_ * 2)(ex) | |
| println(res1) | |
| println(maybeInstance.`<$`("TEST")(Just(10))) | |
| println(ex.fmap(_ * 10)) | |
| println(ex.`<$`("TESTING")) | |
| val times: Int => Int => Int = { a => | |
| { b => | |
| a * b | |
| } | |
| } | |
| val moreTimes: Int => Int => Int => Int = { a => | |
| { b => | |
| { c => | |
| a * b * c | |
| } | |
| } | |
| } | |
| val appRes: Maybe[Int] = maybeInstance.<*>(ex.fmap(times))(Just(2)) | |
| println(appRes) | |
| val xxx = ex.fmap(times) <*> Just(5) | |
| println(xxx) | |
| val two: Maybe[Int] = Just(2) | |
| val abc = (two `<$>` moreTimes) <*> Just(5) <*> Just(6) | |
| println(abc) | |
| val squareMaybeInt: Int => Maybe[Int] = { v => | |
| Just(v * v) | |
| } | |
| val m = two >>= squareMaybeInt >>= squareMaybeInt >>= squareMaybeInt | |
| println(m) | |
| val comped = for { | |
| v <- two | |
| a <- squareMaybeInt(v) | |
| b <- squareMaybeInt(a) | |
| c <- squareMaybeInt(b) | |
| } yield c | |
| println(comped) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment