Dependency Injection in Scala with Jellyfish

January 14, 2013

Delimited continuations allow functional effects to be expressed in a direct style, eliminating the need for nested flatMap callbacks and for comprehensions.

Jellyfish is a Scala library for direct-style functional dependency injection via delimited continuations.

Direct-style effects via delimited continuations

import scala.language.higherKinds

import scala.util.continuations.shift
import scala.util.continuations.reset
import scala.util.continuations.cpsParam

import cats.Monad
import cats.effect.IO
import cats.effect.IOApp
import cats.effect.std.Console

object Main extends IOApp.Simple {

  def extract[F[_]: Monad, A](x: F[A]): A @cpsParam[F[Unit], F[Unit]] =
    shift { k: (A => F[Unit]) =>
      implicitly[Monad[F]].flatMap(x)(k)
    }

  override val run: IO[Unit] =
    reset {
      val x: Int = extract(IO.pure(6))
      val y: Int = extract(IO.pure(7))
      val z: Int = x * y
      Console[IO].println(z)
    }
}

Try it out

This file is literate Scala, and can be run using Codedown:

$ curl https://earldouglas.com/jellyfish.md |
  codedown scala |
  scala-cli \
    --scala 2.12.2 \
    --jvm 17 \
    --compiler-plugin org.scala-lang.plugins:::scala-continuations-plugin:1.0.3 \
    --dependency org.scala-lang.plugins::scala-continuations-library:1.0.3 \
    --dependency org.typelevel::cats-effect:3.5.4 \
    -P:continuations:enable \
    _.scala
42