# `Feel.Runtime.Iteration`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/runtime/iteration.ex#L1)

`for`, `some` and `every` (DMN 1.6, section 10.3.2.14 and Table 50; D-86).

A backend does not loop. It gives this module the **domains**, the **body**, and where they are in the source,
and this module runs the loops, so both backends iterate in the same way, count the same iterations, and end
at the same limit. A domain and the body are functions of the environment, because they are code of the
expression: the interpreter's walk of a node, and a `fun` of the generated code.

  * a **domain** is `fn env, earlier -> {raw, env} end`, where `earlier` is the list of the values of the
    iterators before it. A later domain reads the earlier iterators (`for x in [[1, 2], [3, 4]], y in x`, TCK
    0084 #015), so it is evaluated again for each of their values. `raw` is a value, or `{:through, from, to}`
    for `from..to`, which has no value of its own. With the `:reads` option (below) `earlier` is only the values
    the domain reads.
  * the **body** is `fn env, values, partial -> {value, env} end`, with the value of each iterator, in
    order, and the results so far (`partial`; `[]` when the body does not read it). With the `:partial` option
    (below) the results are given as the list, oldest first (`true`), or as the results a body indexes
    (`:view`).

## What a domain is given

A domain is given the values of the iterators before it, all of them, as a list. That is a list of `k` values for
the domain of the `k`th iterator, and the backend that binds them by name does `k` things with it, so a loop of `n`
iterators costs `n * n / 2` whatever its domains read (D-86). The `:reads` option of `for_loop/4`, `some/4` and
`every/4` is a list with one entry for each domain, `:all` or the places (0 for the first iterator) of the ones
the domain reads, and a domain with places is given the values at them, in that order, and no others. The
backends give places to the domains that have many iterators before them (more than 16) and leave `:all` for the
rest. Without the option every domain is given all of them, as it was before it, so code that was made without it
runs as it did.

## What a body is given as `partial`

A body that reads `partial` as a value (`sum(partial)`, `partial` as an argument, a path, a filter that is not an
index, a nested loop over it) is given the list of the results so far, oldest first: the loop keeps them newest first,
to put one in with a cons, and makes the list for each run of the body, which is `m` cells for the `m`th. That is
what the `:partial` option `true` says. A body that reads it only as `partial[expr]` or `count(partial)` says `:view`,
and is given the results as `Feel.Runtime.Partial` (D-86), that the loop puts each result in as it makes it and the
reads look in, so there is no list to make and a read does not depend on how many results there are
(`Feel.Analysis.Iterations.view/2` is where that is decided, and the backends read it with `Partial.at/4` and
`Partial.count/3`). A loop that is told `true` and does not read `partial` is as it was.

## The loops

The first iterator is the outermost loop and the last varies fastest, so
`for i in [1, 2], j in [3, 4]` is `(1, 3), (1, 4), (2, 3), (2, 4)`. `for` is the list of the bodies, in that order;
`some` is `false or r1 or r2 or ...` and `every` is `true and r1 and r2 and ...`, in the three-valued logic
(`Feel.Runtime.Logic`): a `true` decides a `some` and a `false` an `every`, whatever else is `null`. Every
iteration is evaluated, as every operand of an operator is (D-53), so what a body reports is reported. A
product with no element is `[]`, `false` for `some` and `true` for `every`.

## A strict quantifier

`some` and `every` of a boxed expression (`strict: true`, `Feel.Runtime.Boxed`, D-212) are `null` with an error, for the whole
expression, when the body is a value that is neither a boolean nor `null`: the loop ends there. Without the option a body that is
not a boolean is `null` for the fold, as the three-valued logic has it.

## The domains

| The domain                    | The elements                                                       |
| ----------------------------- | ------------------------------------------------------------------ |
| a list                        | its elements, in order                                             |
| `from..to` of whole numbers   | `from`, `from + 1`, ..., `to`, or down by 1 when `to` is below     |
| `from..to` of dates           | each day from `from` to `to`, or down                              |
| any other value, not `null`   | the value alone, as a list of one (section 10.3.2.9.4), as an info |

Both ends of `from..to` are included. These are `null`, with an error, for the **whole** expression, and
nothing runs: `null` as a domain; a range value, `[1..2]`, which is not `1..2` (TCK 0084 #023 to #025); and
`from..to` of anything but two whole numbers or two dates (`"a".."z"`, `1.5..4`, times, date and times,
durations, `null`, a number and a date).

## Limits

Every element that an iterator takes counts as an iteration, and the run ends, in either mode, with an error of
kind `:limit` when they pass `max_iterations` (`Feel.Runtime.Env.count_iteration/1`). A range is walked, and
not made, so `for i in 1..1000000000 return i` stops at the limit and not at the memory.

The list that a `for` makes is counted as it grows, and the run ends in the same way at the first result over
`max_list_length` (`Feel.Runtime.Env.check_list_length/2`), where it ended when the finished list was refused. The error
is the same, and carries the diagnostics of the run until that result and not those of the iterations that were left
(D-154). A `for` inside another has a list of its own, and `some` and `every` make none.

# `body`

```elixir
@type body() :: (Feel.Runtime.Env.t(), [Feel.Value.t()], [Feel.Value.t()] -&gt;
             {Feel.Value.t(), Feel.Runtime.Env.t()})
```

# `domain`

```elixir
@type domain() :: (Feel.Runtime.Env.t(), [Feel.Value.t()] -&gt;
               {raw(), Feel.Runtime.Env.t()})
```

# `options`

```elixir
@type options() :: %{
  :span =&gt; Feel.Diagnostic.span(),
  :spans =&gt; [Feel.Diagnostic.span()],
  optional(:partial) =&gt; boolean() | :view,
  optional(:strict) =&gt; boolean(),
  optional(:reads) =&gt; [:all | [non_neg_integer()]]
}
```

What the loop is told besides the code: the span of the expression, the span of each domain (for the
diagnostics about it), whether the body reads `partial` and how (`:partial`: `false`, `true` for the list of the
results, `:view` for `Feel.Runtime.Partial`), and what each domain reads (`:reads`, above).

# `raw`

```elixir
@type raw() :: Feel.Value.t() | {:through, Feel.Value.t(), Feel.Value.t()}
```

What a domain gives: a value, or the two ends of `from..to`.

# `every`

```elixir
@spec every(Feel.Runtime.Env.t(), [domain()], body(), options()) ::
  {Feel.Value.t(), Feel.Runtime.Env.t()}
```

`every`: `true and r1 and r2 ...` for the results of the body.

    iex> env = Feel.Runtime.Env.new()
    iex> options = %{span: {0, 5}, spans: [{0, 1}]}
    iex> body = fn env, [i], _partial -> {i != nil and i > 0, env} end
    iex> {false, _env} = Feel.Runtime.Iteration.every(env, [fn env, [] -> {[1, nil], env} end], body, options)
    iex> {true, _env} = Feel.Runtime.Iteration.every(env, [fn env, [] -> {[], env} end], body, options)

# `for_loop`

```elixir
@spec for_loop(Feel.Runtime.Env.t(), [domain()], body(), options()) ::
  {Feel.Value.t(), Feel.Runtime.Env.t()}
```

`for`: the list of the values of the body for each iteration, or `null` with the error of a domain that cannot be
iterated.

    iex> env = Feel.Runtime.Env.new()
    iex> domains = [fn env, [] -> {[Decimal.new(1), Decimal.new(2)], env} end]
    iex> body = fn env, [i], _partial -> {Decimal.add(i, 10), env} end
    iex> {values, _env} = Feel.Runtime.Iteration.for_loop(env, domains, body, %{span: {0, 5}, spans: [{0, 1}]})
    iex> Enum.map(values, &Decimal.to_integer/1)
    [11, 12]

# `some`

```elixir
@spec some(Feel.Runtime.Env.t(), [domain()], body(), options()) ::
  {Feel.Value.t(), Feel.Runtime.Env.t()}
```

`some`: `false or r1 or r2 ...` for the results of the body.

    iex> env = Feel.Runtime.Env.new()
    iex> options = %{span: {0, 5}, spans: [{0, 1}]}
    iex> body = fn env, [i], _partial -> {i == 2, env} end
    iex> {true, _env} = Feel.Runtime.Iteration.some(env, [fn env, [] -> {[1, 2, 3], env} end], body, options)
    iex> {false, _env} = Feel.Runtime.Iteration.some(env, [fn env, [] -> {[], env} end], body, options)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
