eval
Types
A Eval
represents a computation to be run given some context. That “to be
run” part turns out to be quite powerful. By combining Eval
s using some
of the functions in this module, we can build up a computation that has
access to a sort of mutable state that is updated as the computations are
run.
There are three type parameters here, not just two, because an Eval
also
represents a computation that can fail. In many ways, an Eval
is just a
superpowered Result
!
pub opaque type Eval(a, e, ctx)
Functions
pub fn all(evals: List(Eval(a, b, c))) -> Eval(List(a), b, c)
Run a list of Eval
s in sequence and then combine their results into a list.
If any of the Eval
s fail, the whole sequence fails.
📝 Note: you might find this called sequence
in some other languages like
Haskell or PureScript.
pub fn attempt(
eval: Eval(a, b, c),
catch f: fn(c, b) -> Eval(a, b, c),
) -> Eval(a, b, c)
Run an Eval
and then attempt to recover from an error by applying a function
that takes the error value and returns another Eval
.
pub fn from(eval: fn(a) -> #(a, Result(b, c))) -> Eval(b, c, a)
Construct an Eval
from a function that takes some context and returns a pair
of a new context and some Result
value. This is provided as a fallback if
none of the functions here or in eval/context
are getting you where you need
to go: generally you should avoid using this in favour of combining the
other functions in this module!
pub fn from_option(value: Option(a), error: b) -> Eval(a, b, c)
Construct an Eval
from an optional value and an error to throw if that value
is None
. This is useful for situations where you have some function or value
that returns an Option
but is not dependent on the context.
pub fn from_result(value: Result(a, b)) -> Eval(a, b, c)
Construct an Eval
from a result. This is useful for situations where you have
some function or value that returns a Result
but is not dependent on the
context.
pub fn guard(
when requirement: Bool,
return consequence: a,
otherwise do: fn() -> Eval(b, a, c),
) -> Eval(b, a, c)
pub fn map(
eval: Eval(a, b, c),
by f: fn(a) -> d,
) -> Eval(d, b, c)
Transform the value produced by an Eval
using the given function.
📝 Note: you might find this called fmap
or <$>
in some other languages
like Haskell or PureScript. In this context, the Eval
type would be known
as a functor.
pub fn map2(
eval_a: Eval(a, b, c),
eval_b: Eval(d, b, c),
by f: fn(a, d) -> e,
) -> Eval(e, b, c)
📝 Note: you might find this called liftA2
or liftM2
in some other
languages like Haskell or PureScript.
pub fn map_error(
eval: Eval(a, b, c),
by f: fn(b) -> d,
) -> Eval(a, d, c)
Just like map
but for error-producing steps instead. Transforms the error
produced by some Eval
step using the given function.
pub fn replace(
eval: Eval(a, b, c),
with replacement: d,
) -> Eval(d, b, c)
Run an Eval
step but then replace its result with some other fixed value.
Often used in tandem with effectful steps that often do something but don’t
produce any meaninful value (and so are usually Eval(Nil, e, ctx)
).
pub fn replace_error(
eval: Eval(a, b, c),
with replacement: d,
) -> Eval(a, d, c)
Just like replace
but for error-producing steps instead. Replaces the error
thrown by some Eval
step with another, fixed, value.
pub fn return(value: a) -> Eval(a, b, c)
Construct an Eval
that always succeeds with the given value, regardless of
context.
📝 Note: you might find this called pure
or return
in some other languages
like Haskell or PureScript.
pub fn run(eval: Eval(a, b, c), with context: c) -> Result(a, b)
Given an Eval
, actuall perform the computation by also providing the context
that the computation is running in.
pub fn step(eval: Eval(a, b, c), ctx: c) -> #(c, Result(a, b))
Step through an Eval
and get back both it’s result and the context it
produced. This is especially useful if you want to run some computation,
do some other Gleam bits, and then continue with the computation by passing
the produced context to run
or step
again.
pub fn then(
eval: Eval(a, b, c),
do f: fn(a) -> Eval(d, b, c),
) -> Eval(d, b, c)
Run an Eval
and then apply a function that returns another Eval
to the
result. This can be useful for chaining together multiple Eval
s.
📝 Note: you might find this called bind
, >>=
, flatMap
, or andThen
in
some other languages like Haskell, Elm, or PureScript. In this context, the
Eval
type would be known as a monad.
pub fn throw(error: a) -> Eval(b, a, c)
Construct an Eval
that always fails with the given error, regardless of
context. Often used in combination with then
to run some Eval
and then
potentially fail based on the result of that computation.
eval(expr) |> then(fn (y) {
case y == 0.0 {
True ->
throw(DivisionByZero)
False ->
succeed(y)
}
})
pub fn try(
eval: Eval(a, b, c),
then f: fn(a) -> Eval(d, b, c),
) -> Eval(d, b, c)
Run an Eval
and then apply a function that returns another Eval
to the
result. This can be useful for chaining together multiple Eval
s. This is
the same as then
but you might find the try
naming nicer to use
with Gleam’s use
notation.
📝 Note: you might find this called bind
, >>=
, flatMap
, or andThen
in
some other languages like Haskell, Elm, or PureScript. In this context, the
Eval
type would be known as a monad.