effect

Types

The Effect type represents computations that might return early or continue with a value. Each effect specifies:

  1. The type of the continue value (msg)
  2. The type of early return value (early)

You can treat msg as the happy path. The early type is for long jumping.

pub opaque type Effect(msg, early)

A function that handles the successful path of an effect.

pub type Next(msg) =
  fn(msg) -> Nil

A function that handles the early return path of an effect.

pub type Not(early) =
  fn(early) -> Nil

Type representing the absence of an early return value.

pub type Nothing

Functions

pub fn continue(value: a) -> Effect(a, b)

Creates an effect that succeeds with the given value.

let effect: Effect(Int, early) = continue(42)
pub fn from(
  value: a,
  handler: fn(a) -> Effect(b, c),
) -> Effect(b, c)

Creates an effect from a value with a handler to operate on it.

use n: Int <- from(5)
pub fn from_box(
  box: a,
  unbox_fn: fn(a, fn(b) -> Nil) -> c,
  handler: fn(b) -> Effect(d, e),
) -> Effect(d, e)

Creates an effect from a boxed value (like a Promise), using the provided unboxing function (like promise.map) and operates on the unboxed value via the handler.

let promise: Promise(Result(ok, err))
use result: Result(ok, err) <- from_box(promise, promise.map)
use ok: ok <- from_result(result)
pub fn from_option(
  value: Option(a),
  early: b,
  handler: fn(a) -> Effect(c, b),
) -> Effect(c, b)

Creates an effect from an Option, where Some values are passed to the given function and None causes an early return.

pub fn from_result(
  value: Result(a, b),
  handler: fn(a) -> Effect(c, b),
) -> Effect(c, b)

Creates an effect from a Result, where Ok values are passed to the given function and Error values cause an early return.

let str: String = "123"
let result: Result(Int, Nil) = parse_int(str)
use num: Int <- from_result(result)
pub fn handle(
  effect: Effect(a, b),
  handler: fn(Result(a, b)) -> Effect(c, d),
) -> Effect(c, d)

Handles both paths of an effect, allowing transformation into a new effect with potentially different types.

type ShowState {
  ShowSuccess(valid)
  ShowError(err)
}

use res: Result(valid, err) <- handle(validate_input(data))
case res {
  Ok(valid) -> continue(ShowSuccess(valid))
  Error(err) -> continue(ShowError(err))
}
pub fn map(
  effect: Effect(a, b),
  handler: fn(a) -> c,
) -> Effect(c, b)

Transforms the successful values of an effect via the handler.

let effect = continue(5)
use num: Int <- map(effect)
num * 2
pub fn map_early(
  effect: Effect(a, b),
  handler: fn(b) -> c,
) -> Effect(a, c)

Transforms the early return values of an effect via the handler.

type Msg { Msg(String) }
let effect: Effect(msg, String) = throw("some context")
let effect: Effect(msg, Msg) = map_early(effect, Msg)
pub fn perform(
  effect: Effect(a, b),
  handler: fn(Result(a, b)) -> c,
) -> Nil

Executes an effect, handling both paths with a handler.

use res: Result(msg, early) <- perform(effect)
case res {
  Ok(value) -> io.println("Success: " <> value)
  Error(err) -> io.println("Error: " <> err)
}
pub fn pure(
  effect: Effect(a, Nothing),
  handler: fn(a) -> b,
) -> Nil

Executes an effect that is known to be pure (cannot have early returns). The handler only needs to handle the success case.

let effect: Effect(Int, early) = continue(42)
use num: Int <- pure(effect)
num |> int.to_string |> io.println
pub fn then(
  effect: Effect(a, b),
  handler: fn(a) -> Effect(c, b),
) -> Effect(c, b)

Chains together two effects where the second effect depends on the result of the first.

let effect = {
  use a <- then(get_user())
  use b <- then(get_posts(a.id))
  continue(b)
}
pub fn throw(value: a) -> Effect(b, a)

Creates an effect that returns early with the given value.

let effect: Effect(any, String) = throw("Something went wrong")
pub fn unbox(
  box: a,
  unbox_fn: fn(a, fn(b) -> Nil) -> c,
) -> Effect(b, d)

Creates an effect from a boxed value. Primarly used to unbox Promises but can work with other boxed types.

let value: Value = ...
let promise: Promise(Value) = promise.resolve(value)
let effect: Effect(Value, early) = unbox(promise, promise.map)
pub fn wrap_option(value: Option(a), early: b) -> Effect(a, b)

Creates an effect that wraps an option type. The Some variant continues and the None variant returns early with the given early value.

let effect: Effect(Int, String) = wrap_option(Some(69), "It should've been Some tho...")
let effect: Effect(Int, String) = wrap_option(None, "This is None")
pub fn wrap_result(value: Result(a, b)) -> Effect(a, b)

Creates an effect that wraps a result type. The Ok variant continues and the Error variant returns early.

let effect: Effect(Int, early) = wrap_result(Ok(5))
let effect: Effect(msg, String) = wrap_result(Error("wrong!"))
Search Document