SagaSaga
Saga

A practical functional language
with composable effects

Write pure functions, handle the rest with composable effects.
Change behavior without rewriting business logic.
Full type safety. Powered by the BEAM.

fun get_users : Unit -> List User needs {Database}
get_users () = query! "SELECT * FROM users"

# Same function call, two different behaviors:
main () = get_users () with postgres

test "get_admins" (fun () -> {
  let users = get_users () with mock_db
  assert_eq (List.length users) 2
})

CORE CAPABILITIES

Algebraic Effects

Effects are interfaces. Handlers are implementations. Swap them for testing, middleware, or error recovery.

Full Type Inference

Strong static types with inference, traits, and effect tracking. Annotate public APIs; let the compiler infer the rest.

Pattern Matching & ADTs

Exhaustive matching, algebraic data types, records, and pure guards. Safety by design.

Typesafe BEAM Concurrency

Build with lightweight processes, OTP supervision, distribution, and statically checked message passing.

Effects in action

The true power of Saga lies in how it decouples the declaration of what needs to happen from the execution of how it happens.

Read the guide →
example.saga
# Handlers can do more than mock dependencies:
effect Choose {
  fun choose : List a -> a
}

outfit () = {
  let top = choose! ["white", "black"]
  let bottom = choose! ["jeans", "khakis"]
  top <> " + " <> bottom
}

# All combinations
outfit () with all_choices
# => "white + jeans", "white + khakis",
#    "black + jeans", "black + khakis"

# Pick one at random
outfit () with random
# => "black + jeans"