Skip to content

Instantly share code, notes, and snippets.

@chrilves
Created July 27, 2018 15:44
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 chrilves/2fb46d19c220e39f867ae06c1690032f to your computer and use it in GitHub Desktop.
Save chrilves/2fb46d19c220e39f867ae06c1690032f to your computer and use it in GitHub Desktop.
import scala.language.higherKinds
object Toto {
trait Monad[M[_]] {
def pure[A](value: A): M[A]
def flatMap[A,B](ma: M[A], f: A => M[B]): M[B]
final def map[A,B](ma: M[A], f: A => B): M[B] =
flatMap(ma, f `andThen` pure)
// Element neutre a gauche
// pure(v).flatMap(f) = f(v)
// Element neutre à droite
// (ma: M[A]).flatMap(pure) = ma
// Associativité
// ((ma: M[A]).flatMap(f)).flatMap(g)
// =
// (ma: M[A]).flatMap{ (a:A) => (f(a)).flatMap(g) }
}
object Monad {
def apply[M[_]](implicit M : Monad[M]) = M
}
implicit final class MonadOps[M[_], A](val self: M[A])(implicit M : Monad[M]) {
def flatMap[B](f: A => M[B]): M[B] = M.flatMap(self, f)
def map[B](f: A => B): M[B] = M.map(self, f)
}
type Id[A] = A
implicit val idMonadInstance = new Monad[Id] {
def pure[A](value: A): A = value
def flatMap[A,B](ma: A, f: A => B): B = f(ma)
}
final case class IO[A](run: () => A) {
def flatMap[B](f: A => IO[B]): IO[B] = io.flatMap(this, f)
def map[B](f : A => B): IO[B] = flatMap(f `andThen` io.pure)
}
implicit val io = new Monad[IO] {
def pure[A](value: A): IO[A] = IO(() => value)
def flatMap[A,B](ma: IO[A], f: A => IO[B]): IO[B] =
IO(() => f(ma.run()).run())
}
implicit val option = new Monad[Option] {
def pure[A](value: A): Option[A] = Some(value)
def flatMap[A,B](ma: Option[A], f: A => Option[B]): Option[B] =
ma match {
case Some(a) => f(a)
case None => None
}
}
def f(x : Option[Int], y: Option[Int], z: Option[Int]): Option[Int] =
for {
vx <- x
vy <- y
vz <- z
} yield vx + vy + vz
trait MonadTrans[F[_[_], _]] {
def lift[M[_]: Monad,A](ma: M[A]): F[M, A]
def monad[M[_]: Monad]: Monad[ ({type G[B] = F[M,B] })#G ]
}
final case class OptionT[M[_], A](value: M[Option[A]])
implicit val optionT = new MonadTrans[OptionT] {
def lift[M[_]: Monad,A](ma: M[A]): OptionT[M, A] = {
val value: M[Option[A]] = ma.map(Some(_))
OptionT[M, A](value)
}
def monad[M[_]: Monad] = new Monad[ ({type G[B] = OptionT[M,B]})#G ] {
def pure[A](value: A): OptionT[M, A] =
OptionT[M, A](Monad[M].pure(Some(value)))
def flatMap[A,B](ma: OptionT[M, A], f: A => OptionT[M, B]): OptionT[M, B] =
OptionT[M,B](
ma.value.flatMap { (oa: Option[A]) =>
oa match {
case Some(a) =>
f(a).value
case None =>
Monad[M].pure(None)
}
}
)
}
}
trait Monoid[A] {
val zero: A
def combine(x: A, y: A): A
// (x + y) + y = x + (y + z) Associativité
// x + zero = x = zero + z Element neutre
}
def echo(s: String): IO[Unit] = IO(() => println(s))
def g(x : IO[Option[Int]], y: IO[Option[Int]], z: IO[Option[Int]]): IO[Option[Int]] = {
type G[A] = OptionT[IO, A]
implicit val optionTIO: Monad[G] = optionT.monad[IO]
(
for {
vx <- (OptionT(x) : G[Int])
_ <- (optionT.lift(echo("toto"): IO[Unit]): G[Unit])
vy <- (OptionT(y) : G[Int])
vz <- (OptionT(z) : G[Int])
} yield vx + vy + vz
).value
}
}
import Toto._
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment