Created
March 29, 2025 13:31
-
-
Save kubukoz/9cf1f6698f9c3e4c7280b1d5e16d3979 to your computer and use it in GitHub Desktop.
reviving an old concept for a new tagless final encoding in scala 3, thanks to inspiration from Noel Welsh's scalar 2025 talk
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
//> using dep org.typelevel::cats-effect:3.6.0 | |
import cats.effect.IO | |
import cats.effect.unsafe.IORuntime | |
import cats.effect.IOApp | |
enum Permission { | |
case View | |
case Edit | |
case Both(p1: Permission, p2: Permission) | |
} | |
trait Dsl { | |
type F[_] | |
def requires(p: Permission): F[Unit] | |
def sequence[A, B](p1: F[A], p2: F[B]): F[B] | |
} | |
object Dsl { | |
type Program[A] = (dsl: Dsl) ?=> dsl.F[A] | |
def requires( | |
p: Permission | |
): Program[Unit] = dsl.requires(p) | |
def sequence[A, B]( | |
p1: Program[A], | |
p2: Program[B], | |
): Program[B] = dsl.sequence(p1, p2) | |
def dsl( | |
using instance: Dsl | |
): instance.type = instance | |
def compile[A](f: Program[A]): (dryRun: Boolean) => IO[Option[A]] = | |
dryRun => { | |
val describe = | |
new Dsl: | |
type F[A] = String | |
def requires(p: Permission): String = s"requires $p" | |
def sequence[A, B](p1: String, p2: String): String = s"$p1, $p2" | |
val run = | |
new Dsl: | |
type F[A] = IO[A] | |
def requires(p: Permission): IO[Unit] = IO.println(s"checking $p") | |
def sequence[A, B](p1: IO[A], p2: IO[B]): IO[B] = p1 *> p2 | |
if (dryRun) | |
IO.println( | |
f( | |
using describe | |
) | |
).as(None) | |
else | |
f( | |
using run | |
).map(Some(_)) | |
} | |
} | |
object Main extends IOApp.Simple { | |
val p: Dsl.Program[Unit] = Dsl.sequence( | |
Dsl.requires(Permission.View), | |
Dsl.requires(Permission.Edit), | |
) | |
def run: IO[Unit] = Dsl | |
.compile(p)(dryRun = false) | |
.flatMap(IO.println(_)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment