From 0da1bc49f6dee06dbbe10c33619251076c44359c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Brachtha=CC=88user?= Date: Sun, 7 Jan 2024 18:01:17 +0100 Subject: [PATCH] Use Scala's new capture checking --- build.sbt | 2 +- .../scala/monadic/examples/Capabilities.scala | 2 +- .../main/scala/monadic/examples/Capture.scala | 91 +++++++++++++++++++ core/src/main/scala/monadic/syntax.scala | 6 +- 4 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 core/src/main/scala/monadic/examples/Capture.scala diff --git a/build.sbt b/build.sbt index 7239515..b9d1c3e 100644 --- a/build.sbt +++ b/build.sbt @@ -1,7 +1,7 @@ lazy val commonSettings = Seq( version := "0.1.0-SNAPSHOT", - scalaVersion := "3.3.1", + scalaVersion := "3.4.0-RC1-bin-20240105-d2cc3ae-NIGHTLY", // javaOptions ++= Seq( // "-XX:-DetectLocksInCompiledFrames", // "-XX:+UnlockDiagnosticVMOptions", diff --git a/core/src/main/scala/monadic/examples/Capabilities.scala b/core/src/main/scala/monadic/examples/Capabilities.scala index 482a26c..23ec2d4 100644 --- a/core/src/main/scala/monadic/examples/Capabilities.scala +++ b/core/src/main/scala/monadic/examples/Capabilities.scala @@ -92,7 +92,7 @@ object library { /** * Provide services to the computation, fully satisfying its requirements */ - inline def provide(service: R): EFF[Any, E, A] = effectful { this.force()(using service) } + infix inline def provide(service: R): EFF[Any, E, A] = effectful { this.force()(using service) } inline def catchAll[R1 <: R, E1, A1 >: A](handler: E => Eff[R1, E1, A1]): EFF[R1, E1, A1] = effectful { try { this.force()(using use[R1], ()) } diff --git a/core/src/main/scala/monadic/examples/Capture.scala b/core/src/main/scala/monadic/examples/Capture.scala new file mode 100644 index 0000000..9231123 --- /dev/null +++ b/core/src/main/scala/monadic/examples/Capture.scala @@ -0,0 +1,91 @@ +package monadic +package examples +package capture + +import language.experimental.captureChecking + + +object redesign extends App { + + trait Effect { + + /** + * The monadic type constructor + */ + type M[A] + + /** + * The Monad instance for [[ M ]] + */ + def Monad: Monadic[M] + + /** + * The interface of effect operations, supported by the monad + */ + type Operations + + /** + * Implementation of the effect operations in terms of monadic reflection. + */ + def Operations: CanReflect[M] ?=> Operations + + /** + * Runs a [[ program ]] that can make use of the effect [[ Operations ]] + * to compute a result of type [[ A ]] in monad [[ M ]]. + */ + def apply[A](program: Operations^ ?=> A): M[A] = + Monad.reify { cap ?=> program(using Operations) } + + /** + * Makes the effect operations available on the effect instance + */ + implicit inline def api(self: this.type)(using impl: Operations^): Operations^{impl} = impl + } + + + trait State[S] { + def get(): S + def set(s: S): Unit + def update(fn: S => S): Unit + } + + class StateMonad[S] extends Effect { + + type M[A] = S => (S, A) + + class Operations(using CanReflect[M]) extends State[S] { + def get() = Monad.reflect(s => (s, s)) + def set(s: S) = Monad.reflect(_ => (s, ())) + def update(fn: S => S) = Monad.reflect(s => (fn(s), ())) + } + + def Operations = new Operations + + class Monad extends Monadic[M] { + def pure[A](a: A): M[A] = s => (s, a) + def sequence[X, R](init: M[X])(f: X => Either[M[X], M[R]]): M[R] = + @scala.annotation.tailrec + def go(prog: M[X], state: S): (S, R) = + val (newState, x) = prog(state) + f(x) match { + case Left(mx) => go(mx, newState) + case Right(res) => res(newState) + } + s => go(init, s) + } + // with capture checking enabled, this cannot be defined by an object + val Monad = new Monad + } + + object Number extends StateMonad[Int] + + val result = Number { + while (Number.get() > 0) { + Number.set(Number.get() - 1) + //if (Number.get() == 1) throw new Exception("Abort!") + } + } + try { println(result(1000)) } catch { + case e: Exception => e.printStackTrace() + } +} diff --git a/core/src/main/scala/monadic/syntax.scala b/core/src/main/scala/monadic/syntax.scala index e99e5a6..73bd683 100644 --- a/core/src/main/scala/monadic/syntax.scala +++ b/core/src/main/scala/monadic/syntax.scala @@ -1,14 +1,14 @@ package monadic package syntax - type in[A, M[_]] = CanReflect[M] ?=> A + infix type in[A, M[_]] = CanReflect[M] ?=> A inline def reify[M[_]: Monadic]: ReifyBuilder[M] = ReifyBuilder() case class ReifyBuilder[M[_]]()(using M: Monadic[M]) { - inline def in[R](prog: R in M) = M.reify[R] { prog } + infix inline def in[R](prog: R in M) = M.reify[R] { prog } inline def apply[R](prog: R in M) = M.reify[R] { prog } } extension [M[_], R](mr: M[R]) - inline def reflect(using r: CanReflect[M]): R = r.reflect(mr) \ No newline at end of file + inline def reflect(using r: CanReflect[M]): R = r.reflect(mr)