# 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.

✨ Tip: in other languages there might be a more general version of this
function called `traverse`

. You can easily create that by combining `list.map`

and `all`

!

```
[ 1, 2, 3 ]
|> list.map(eval.succeed)
|> eval.all
// => Eval(List(Int), e, ctx)
```

```
pub fn apply(eval_f: Eval(fn(a) -> b, c, d), to eval_a: Eval(
a,
c,
d,
)) -> Eval(b, c, d)
```

Intended to be used in combination with the `succeed{N}`

functions. This runs
an `Eval`

and then *applies* it to the result of the second argument.

```
case expr {
Add(lhs, rhs) ->
succeed2(fn (x, y) { x + y })
|> apply(eval(lhs))
|> apply(eval(rhs))
...
}
```

📝 Note: you might find this called `ap`

or `<*>`

in some other languages
like Haskell or PureScript. In this context, the `Eval`

type would be known
as an *applicative functor*.

```
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 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 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 succeed(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 succeed2(f: fn(a, b) -> c) -> Eval(
fn(a) -> fn(b) -> c,
d,
e,
)
```

Like `succeed`

, but used specifically with a function that takes two arguments.
This is most commonly used with `apply`

to run a series of `Eval`

s in a
pipeline to build up some more complex value.

📝 Note: when used this way, this is often known as “applicative programming”.
In this context, the `Eval`

type would be known as an *applicative functor*.

❓ Why are these `succeedN`

functions necessary? In other functional programming
languages, like Elm or Haskell, functions are *curried* which means all
functions are actually just a series of single-argument functions that return
other functions. We can achieve this in Gleam by using the `function.curryN`

functions.

We need the functions passed to `succeed`

to be curried to work properly with
`apply`

, and so we provide a handful of these `succeedN`

functions that do
the currying for you.

```
pub fn succeed3(f: fn(a, b, c) -> d) -> Eval(
fn(a) -> fn(b) -> fn(c) -> d,
e,
f,
)
```

Like `succeed`

, but used specifically with a function that takes three arguments.
This is most commonly used with `apply`

to run a series of `Eval`

s in a
pipeline to build up some more complex value.

```
pub fn succeed4(f: fn(a, b, c, d) -> e) -> Eval(
fn(a) -> fn(b) -> fn(c) -> fn(d) -> e,
e,
f,
)
```

Like `succeed`

, but used specifically with a function that takes four arguments.
This is most commonly used with `apply`

to run a series of `Eval`

s in a
pipeline to build up some more complex value.

```
pub fn succeed5(f: fn(a, b, c, d, e) -> f) -> Eval(
fn(a) -> fn(b) -> fn(c) -> fn(d) -> fn(e) -> f,
e,
g,
)
```

Like `succeed`

, but used specifically with a function that takes five arguments.
This is most commonly used with `apply`

to run a series of `Eval`

s in a
pipeline to build up some more complex value.

```
pub fn succeed6(f: fn(a, b, c, d, e, f) -> g) -> Eval(
fn(a) -> fn(b) -> fn(c) -> fn(d) -> fn(e) -> fn(f) -> g,
e,
h,
)
```

Like `succeed`

, but used specifically with a function that takes six arguments.
This is most commonly used with `apply`

to run a series of `Eval`

s in a
pipeline to build up some more complex value.

```
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)
}
})
```