1+ import scala .util .boundary
2+ import runtime .suspend
3+
4+ trait Monad [F [_]]:
5+
6+ /** The unit value for a monad */
7+ def pure [A ](x : A ): F [A ]
8+
9+ extension [A ](x : F [A ])
10+ /** The fundamental composition operation */
11+ def flatMap [B ](f : A => F [B ]): F [B ]
12+
13+ /** The `map` operation can now be defined in terms of `flatMap` */
14+ def map [B ](f : A => B ) = x.flatMap(f.andThen(pure))
15+
16+ end Monad
17+
18+ trait CanReflect [M [_]]:
19+ def reflect [R ](mr : M [R ]): R
20+
21+ trait Monadic [M [_]: Monad ]:
22+
23+ /**
24+ * Embedding of pure values into the monad M
25+ */
26+ def pure [A ](a : A ): M [A ]
27+
28+ /**
29+ * Sequencing of monadic values
30+ *
31+ * Implementations are required to implement sequencing in a stack-safe
32+ * way, that is they either need to implement trampolining on their own
33+ * or implement `sequence` as a tail recursive function.
34+ *
35+ * Actually the type X can be different for every call to f...
36+ * It is a type aligned sequence, but for simplicity we do not enforce this
37+ * here.
38+ */
39+ def sequence [X , R ](init : M [X ])(f : X => Either [M [X ], M [R ]]): M [R ]
40+
41+ /**
42+ * Helper to summon and use an instance of CanReflect[M]
43+ */
44+ def reflect [R ](mr : M [R ])(using r : CanReflect [M ]): R = r.reflect(mr)
45+
46+ /**
47+ * Reify a computation into a monadic value
48+ */
49+ def reify [R ](prog : CanReflect [M ] ?=> R ): M [R ] =
50+ boundary [M [R ]]:
51+ given CanReflect [M ] with
52+ def reflect [R2 ](mr : M [R2 ]): R2 =
53+ suspend [R2 , M [R ]] (k => mr.flatMap(k.resume))
54+ pure(prog)
55+
56+ end Monadic
0 commit comments