Created
April 23, 2025 10:41
-
-
Save lachezar/064fc720b28f235550dcf24b4af97c8b to your computer and use it in GitHub Desktop.
Monads with for-comprehensions
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
enum MyOption[+A]: | |
case MyNone | |
case MySome(a: A) | |
// in case we don't want to have extension for some reason | |
// type M = [X] =>> MyOption[X] | |
// def flatMap[B](f: A => M[B]): M[B] = summon[MyMonad[M]].flatMap(this)(f) | |
// def map[B](f: A => B)(using myMonad: MyMonad[M]): M[B] = | |
// myMonad.flatMap(this)(a => myMonad.pure(f(a))) | |
import MyOption.* | |
trait MyMonad[M[A]] { | |
def flatMap[A, B](m: M[A])(f: A => M[B]): M[B] | |
def pure[A](a: A): M[A] | |
// define map in terms of flatMap and pure | |
// def map[A, B](m: M[A])(f: A => B): M[B] = flatMap(m)(a => pure(f(a))) | |
} | |
given moMonad: MyMonad[MyOption] = new MyMonad[MyOption] { | |
override def flatMap[A, B](m: MyOption[A])(f: A => MyOption[B]): MyOption[B] = | |
m match | |
case MyNone => MyNone | |
case MySome(a) => f(a) | |
override def pure[A](a: A): MyOption[A] = MySome(a) | |
} | |
extension [A, M[+A]: MyMonad](m: M[A]) | |
def flatMap[B](f: A => M[B]): M[B] = summon[MyMonad[M]].flatMap(m)(f) | |
def map[B](f: A => B)(using myMonad: MyMonad[M]): M[B] = | |
myMonad.flatMap(m)(a => myMonad.pure(f(a))) | |
def getName: MyOption[String] = MySome("Tom") | |
def getPass: MyOption[String] = MySome("secret") | |
def getAge: MyOption[Int] = MySome(42) | |
val res: MyOption[(String, String, Int)] = for { | |
name <- getName | |
pass <- getPass | |
age <- getAge | |
} yield (name, pass, age) | |
@main | |
def main(args: String*): Unit = { | |
println(res) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment