Skip to content

Instantly share code, notes, and snippets.

@sshark
Last active May 20, 2024 15:41
Show Gist options
  • Save sshark/6a169bedfa97718dd72eb0738fbb046f to your computer and use it in GitHub Desktop.
Save sshark/6a169bedfa97718dd72eb0738fbb046f to your computer and use it in GitHub Desktop.
An exercise to implement Monad in Scala 3
trait Functor[F[_]]:
def map[A, B](fa: F[A])(f: A => B): F[B]
trait Monad[F[_]] extends Functor[F]:
def unit[A](a: A): F[A]
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(x => unit(f(x)))
object Monad:
def apply[F[_]](using ev: Monad[F]): Monad[F] = ev
object MonadSyntax:
extension[F[_], A](fa: F[A])(using ev: Monad[F])
def flatMap[B](f: A => F[B]): F[B] = ev.flatMap(fa)(f)
def map[B](f: A => B): F[B] = ev.map(fa)(f)
trait MyBox[+A]
case class FilledBox[A](x: A) extends MyBox[A]
case object EmptyBox extends MyBox[Nothing]
object MyBox:
def apply[A](a: A): MyBox[A] = FilledBox(a)
def empty: MyBox[Nothing] = EmptyBox
given Monad[MyBox] with
override def unit[A](a: A) = FilledBox(a)
override def flatMap[A, B](fa: MyBox[A])(f: A => MyBox[B]): MyBox[B] =
fa match
case FilledBox(x) => f(x)
case EmptyBox => EmptyBox
import MonadSyntax.*
def showMyBox[A](box: MyBox[A]): String =
box match
case FilledBox(x) => s"The result is $x"
case _ => "Nothing there"
val result = for {
a <- MyBox(1)
b <- MyBox(2)
} yield a + b
println(showMyBox(result))
val empty = for {
a <- MyBox(1)
_ <- MyBox.empty
} yield a
println(showMyBox(empty))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment