marcinzh/turbolift
Algebraic Effects for Scala 3
{ "createdAt": "2019-04-14T18:00:05Z", "defaultBranch": "master", "description": "Algebraic Effects for Scala 3", "fullName": "marcinzh/turbolift", "homepage": "https://marcinzh.github.io/turbolift/", "language": "Scala", "name": "turbolift", "pushedAt": "2025-10-10T11:48:48Z", "stargazersCount": 79, "topics": [ "algebraic-effects", "functional-programming", "scala" ], "updatedAt": "2025-11-17T16:06:16Z", "url": "https://github.com/marcinzh/turbolift"}Turbolift: Algebraic Effects for Scala 3.
Section titled “Turbolift: Algebraic Effects for Scala 3.”Visit the microsite for description.
See also:
| Project | Description |
|---|---|
| DaaE | Demo: a debugger implemented as an effect |
| Spot | Cats-Effect instances for Turbolift’s IO effect |
| Enterprise | HTTP server implemented using Turbolift’s effects |
| Beam | Streams implemented with Turbolift’s effects |
| Effect Zoo | Microbenchmark suite for several effect systems, including Turbolift |
Example
Section titled “Example”Runnable with scala-cli.
[!IMPORTANT] Turbolift requires Java 11 or newer.
//> using scala "3.3.6"//> using dep "io.github.marcinzh::turbolift-core:0.122.0"import turbolift.!!import turbolift.effects.{Reader, State, Error}
@main def main = val program = for a <- State.get[Int] b <- Reader.ask[Int] c <- if b != 0 then !!.pure(a / b) else Error.raise(s"Tried to divide $a by zero") _ <- State.put(c) yield ()
val result = program .handleWith(State.handler(100)) .handleWith(Reader.handler(3)) .handleWith(Error.handler) .run
println(result) // Right(((),33))
Same, but with [bindless]!(modules/bindless) syntax extension (async/await alike):
//> using scala "3.3.6"//> using dep "io.github.marcinzh::turbolift-core:0.122.0"//> using dep "io.github.marcinzh::turbolift-bindless:0.122.0"import turbolift.!!import turbolift.effects.{Reader, State, Error}import turbolift.bindless._
@main def main = val program = `do`: val a = State.get[Int].! val b = Reader.ask[Int].! val c = if b != 0 then a / b else Error.raise(s"Tried to divide $a by zero").! State.put(c).!
val result = program .handleWith(State.handler(100)) .handleWith(Reader.handler(3)) .handleWith(Error.handler) .run
println(result) // Right(((),33))
Same as the first example, but using monomorphized effect instances:
- 👍 Better for modularity (see Labeled Effects).
- 👍 QOL: Helps type inference and improves clarity of error messages.
- 👎 Slightly more verbose, since effect instance definitions are required (e.g.
case object MyEffect extends SomeEffect).
//> using scala "3.3.6"//> using dep "io.github.marcinzh::turbolift-core:0.122.0"import turbolift.!!import turbolift.effects.{ReaderEffect, StateEffect, ErrorEffect}
@main def main = // 👉 Definitions of custom effect instances: case object MyReader extends ReaderEffect[Int] case object MyState extends StateEffect[Int] case object MyError extends ErrorEffect[String]
val program = for a <- MyState.get // 👉 No need for explicit type parameter: `get[Int]` b <- MyReader.ask // 👉 No need for explicit type parameter: `ask[Int]` c <- if b != 0 then !!.pure(a / b) else MyError.raise(s"Tried to divide $a by zero") _ <- MyState.put(c) yield ()
val result = program .handleWith(MyState.handler(100)) .handleWith(MyReader.handler(3)) .handleWith(MyError.handler) .run
println(result) // Right(((),33))
See also [examples]!(modules/examples/src/main/scala/examples/) folder. Runnable with sbt:
sbt examples/runUsage in SBT
Section titled “Usage in SBT”libraryDependencies += "io.github.marcinzh" %% "turbolift-core" % "0.122.0"Optionally, for the [bindless]!(modules/bindless) syntax extension:
libraryDependencies += "io.github.marcinzh" %% "turbolift-bindless" % "0.122.0"