Maven Central Version javadoc

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

Runnable with scala-cli.

Important

Turbolift requires Java 11 or newer.

//> using scala "3.3.6"
//> using dep "io.github.marcinzh::turbolift-core:0.116.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 syntax extension (async/await alike):

//> using scala "3.3.6"
//> using dep "io.github.marcinzh::turbolift-core:0.116.0"
//> using dep "io.github.marcinzh::turbolift-bindless:0.116.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.116.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 folder. Runnable with sbt:

sbt examples/run

Usage in SBT

libraryDependencies += "io.github.marcinzh" %% "turbolift-core" % "0.116.0"

Optionally, for the bindless syntax extension:

libraryDependencies += "io.github.marcinzh" %% "turbolift-bindless" % "0.116.0"