# Types

## Eval

</>

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

## all

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

## apply

</>
``````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 {
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.

## attempt

</>
``````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`.

## from

</>
``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!

## from_option

</>
``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.

## from_result

</>
``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.

## map

</>
``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.

## map2

</>
``````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.

## map_error

</>
``````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.

## replace

</>
``````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)`).

## replace_error

</>
``````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.

## run

</>
``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.

## step

</>
``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.

## succeed

</>
``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.

## succeed2

</>
``````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.

## succeed3

</>
``````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.

## succeed4

</>
``````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.

## succeed5

</>
``````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.

## succeed6

</>
``````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.

## then

</>
``````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.

## throw

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