Skip to content

Instantly share code, notes, and snippets.

@anthonynsimon
Last active June 22, 2018 23:13
Show Gist options
  • Save anthonynsimon/c9384d2ca04c9b2cf8390d3511de68a6 to your computer and use it in GitHub Desktop.
Save anthonynsimon/c9384d2ca04c9b2cf8390d3511de68a6 to your computer and use it in GitHub Desktop.
FP playground
trait Functor[F[_], A] {
def fmap[B](f: (A) => B): F[B]
}
trait Applicative[F[_], A, B] {
def liftA(f: F[A]): F[B]
}
def fmap[A, B](f: (A) => B): (Option[A]) => Option[B] = {
case Some(x) => Option(f(x))
case None => None
}
def liftA[A, B](f: Option[(A) => B]): Option[A] => Option[B] = {
case Some(x) => f.fmap(ff => ff(x))
case None => None
}
def compose[A, B, C](f: (A) => B, g: (B) => C): (A) => C = x => g(f(x))
implicit class optionFunctor[A](x: Option[A]) extends Functor[Option, A] {
override def fmap[B](f: A => B): Option[B] = x match {
case Some(v) => Option(f(v))
case None => None
}
}
implicit class optionApplicative[A, B](x: Option[(A) => B]) extends Applicative[Option, A, B] {
override def liftA(v: Option[A]): Option[B] = x match {
case Some(f) => fmap(f)(v)
case None => None
}
}
def square: (Int) => Int = x => x * x
def cube: (Int) => Int = square compose square
Option(2) fmap square
(None: Option[Int]) fmap square
liftA (Option(square)) (Option(2))
Option(square) liftA Option(2)
trait Functor [C[_], A] {
def fmap[B](f: (A) => B): C[B]
}
sealed trait Maybe[+A]
object Maybe {
def apply[A](v: A): Maybe[A] = Just(v)
}
case object Nothing extends Maybe[Nothing]
case class Just[A](v: A) extends Maybe[A]
implicit class MaybeFunctor[A](m: Maybe[A]) extends Functor[Maybe, A] {
def fmap[B](f: A => B): Maybe[B] = m match {
case Nothing => Nothing
case Just(v) => Maybe(f(v))
}
}
Just(10) fmap (x => x + 2)
Just("").fmap(_ + "101")
//Just(10) liftA Maybe((x: Int) => x * x)
//Maybe((x: Int) => x * x) liftA Just(10)
import scala.concurrent.{ExecutionContext, Future}
object Monads extends App {
trait Monad[F[_]] {
def flatMap[A, B](a: F[A], f: A => F[B]): F[B]
def pure[A](a: A): F[A]
}
case class User(id: Int)
def findUser[F[_]](id: Int)(implicit m: Monad[F]): F[User] = {
m.flatMap(m.pure(id), (x: Int) => m.pure(User(x)))
}
def deleteUser[F[_]](user: User)(implicit m: Monad[F]): F[User] = {
m.flatMap(m.pure(user), (user: User) => m.pure(user.copy(-1)))
}
implicit def futureMonad(implicit executionContext: ExecutionContext): Monad[Future] = new Monad[Future] {
override def pure[A](a: A): Future[A] = Future.successful(a)
override def flatMap[A, B](a: Future[A], f: A => Future[B]): Future[B] = a.flatMap(f)
}
case class Id[A](a: A)
implicit def idMonad: Monad[Id] = new Monad[Id] {
override def pure[A](a: A): Id[A] = Id(a)
override def flatMap[A, B](a: Id[A], f: A => Id[B]): Id[B] = f(a.a)
}
import scala.concurrent.ExecutionContext.Implicits.global
def program[F[_]](implicit m: Monad[F]): F[User] = {
m.flatMap(findUser[F](5), (x: User) => deleteUser[F](x))
}
val x = program[Future]
}
class Monad[A](value: A) {
def get: A = value
def map[B](f: A => B): Monad[B] = {
Monad(f(value))
}
def flatMap[B](f: A => Monad[B]): Monad[B] = {
f(value)
}
}
object Monad {
def apply[A](value: A): Monad[A] = new Monad(value)
}
Monad(15)
.map(_ + 10)
.flatMap(x => Monad(x + 20))
.get
val z = for {
x <- Monad(15)
y <- Monad(x + 10)
} yield y
z.get
Monad(15)
.map(_ + 10)
.flatMap(x => Monad(s"hello $x"))
.get
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment