# `Feel.Analysis.Iterations`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/analysis/iterations.ex#L1)

The types of `for`, `some` and `every` (D-86), which the analyzer reads off the types of the domains and of the body.

What the iterator is bound to is the **element** of the domain's type, as `Feel.Runtime.Iteration` takes it:

  * a list gives the type of its elements, so `for i in [1, 2, 3]` has an `i` that is `number in 1, 2, 3`, and a
    list of the declared type `list<number>` gives `number | Null`;
  * `from..to` gives a `number` when both ends can be numbers and a `date` when both can be dates;
  * a value that is not a list, a range or `null` is the element itself (a list of one);
  * `null` and a range (`[1..2]`, which is not `1..2`) have no element: the expression is `null` with an error;
  * `Any` is a list of anything or a value: its element is `Any`, and it can fail.

Each domain also says whether it **can fail**, which makes the whole expression `null`, so the type of a `for` is a
list of the type of its body and `Null` where a domain can fail, and whether it **fails always**, which the analyzer
warns about.

A `some` is `true` if its body can be `true` for an element, `false` if it can be `false` for all of them or if there
is no element, and `null` if the body can be `null` or something that is not a boolean, or a domain can fail; an `every`
is the same with `true` and `false` changing places (Table 50).

# `domain`

```elixir
@type domain() :: %{
  elements: Feel.Type.Union.t(),
  fail?: boolean(),
  always_fails?: boolean()
}
```

What the type of a domain gives: the elements, whether it can fail, and whether it always does.

# `elements`

```elixir
@spec elements(Feel.Type.Union.t()) :: domain()
```

The elements of a domain that is an expression, from its type.

    iex> Feel.Analysis.Iterations.elements([{:list, [:number]}])
    %{elements: [:number], fail?: false, always_fails?: false}
    iex> Feel.Analysis.Iterations.elements([{:list, [:number]}, :null])
    %{elements: [:number], fail?: true, always_fails?: false}
    iex> Feel.Analysis.Iterations.elements([:string])
    %{elements: [:string], fail?: false, always_fails?: false}
    iex> Feel.Analysis.Iterations.elements([:null])
    %{elements: [:null], fail?: true, always_fails?: true}

# `for_type`

```elixir
@spec for_type(Feel.Type.Union.t(), boolean()) :: Feel.Type.Union.t()
```

The type of a `for`: a list of the type of the body, and `Null` where a domain can fail.

# `nonempty?`

```elixir
@spec nonempty?(Feel.Type.Union.t()) :: boolean()
```

Whether a domain of this type has an element for sure: it is a value that is not a list, a range or `null`, and so a list of one.

# `quantifier_over`

```elixir
@spec quantifier_over(:some | :every, [Feel.Type.Union.t(), ...]) ::
  Feel.Type.Union.t()
```

The type of a `some` or an `every` over a domain of which every element is tested as its own (D-170): `bodies` is the type of
the test for each element, and there is one at least. The run folds the results from `false` (`some`) or `true` (`every`) with
the three-valued `or` or `and` (Table 50), so `some` is `true` if a test can be, `false` if all can be, and `null` if no test
is `true` and some is neither `true` nor `false`; `every` is the other way round. A `some` over `1, 2, 3` with `i > 2` is
`true` for the test of `3`, whatever `i > 2` is for the others.

    iex> Feel.Analysis.Iterations.quantifier_over(:some, [[{:boolean, false}], [{:boolean, false}], [{:boolean, true}]])
    [{:boolean, true}]
    iex> Feel.Analysis.Iterations.quantifier_over(:some, [[{:boolean, false}], [{:boolean, false}]])
    [{:boolean, false}]
    iex> Feel.Analysis.Iterations.quantifier_over(:some, [[{:boolean, false}], [:boolean, :null]])
    [:boolean, :null]
    iex> Feel.Analysis.Iterations.quantifier_over(:every, [[{:boolean, true}], [{:boolean, false}]])
    [{:boolean, false}]
    iex> Feel.Analysis.Iterations.quantifier_over(:every, [[{:boolean, true}], [{:boolean, true}, :null]])
    [{:boolean, true}, :null]

# `quantifier_type`

```elixir
@spec quantifier_type(
  :some | :every,
  Feel.Type.Union.t(),
  :always | :never | :maybe,
  boolean()
) ::
  Feel.Type.Union.t()
```

The type of a `some` (`kind` `:some`) or an `every`, from the type of the body.

`emptiness` says whether the product of the domains is empty: `:always`, `:never`, or `:maybe`. `fail?` says that a
domain can fail.

    iex> Feel.Analysis.Iterations.quantifier_type(:some, [{:boolean, true}], :never, false)
    [{:boolean, true}]
    iex> Feel.Analysis.Iterations.quantifier_type(:some, [{:boolean, true}], :maybe, false)
    [:boolean]
    iex> Feel.Analysis.Iterations.quantifier_type(:some, [{:boolean, true}], :always, false)
    [{:boolean, false}]
    iex> Feel.Analysis.Iterations.quantifier_type(:every, [:boolean, :null], :never, false)
    [:boolean, :null]
    iex> Feel.Analysis.Iterations.quantifier_type(:every, [{:boolean, true}], :never, false)
    [{:boolean, true}]

# `through`

```elixir
@spec through(Feel.Type.Union.t(), Feel.Type.Union.t()) :: domain()
```

The elements of `from..to`, from the types of its ends: whole numbers when both can be numbers, and dates when both
can be dates. It fails where an end can be `null` or of another kind, or a number that is not whole; an end that is
a single whole number (`1..10`) is all that a number is known to be whole by.

    iex> Feel.Analysis.Iterations.through([:number, :null], [:number])
    %{elements: [:number], fail?: true, always_fails?: false}
    iex> Feel.Analysis.Iterations.through([:date], [:date])
    %{elements: [:date], fail?: false, always_fails?: false}
    iex> Feel.Analysis.Iterations.through([:string], [:string])
    %{elements: [:null], fail?: true, always_fails?: true}

# `view`

```elixir
@spec view(Feel.IR.t(), pos_integer()) :: {:view, Feel.IR.t()} | :list
```

Whether the body of a `for` reads `partial` only by index and count (D-86), and the body with those reads as nodes
of their own. `id` is the id of the frame that binds `partial` for the loop (`meta.id` of the `:local` nodes that read
it), which tells its reads from those of a `partial` that something inside the body binds again.

A read is `partial[index]`, a filter whose brackets can only be a number (`:index`, which `Feel.Analysis.Filters.mode/2`
decides), and `count(partial)` as a call by position of the function of DMN 1.6: the brackets of another mode can be a
predicate or whatever the value says, and a call by name or one that an extension may answer is checked or answered as
the function sees fit. They become `{:partial_at, meta, index}` and `{:partial_count, meta}`, which the backends run
with `Feel.Runtime.Partial` and not with the list of the results. A body with any other read of `partial` (an argument,
`partial` alone, a path, the brackets of a predicate, a name that a filter may read as an entry of its elements, a loop
over it) is `:list` and is not changed: it is given the list, as it always was.

    iex> {:ok, ast} = Feel.parse("for i in 1..3 return if i < 3 then 1 else partial[i - 1] + count(partial)")
    iex> {:ok, %{ir: {:for, %{partial: partial}, _iterators, _body}}} = Feel.Analysis.Analyzer.analyze(ast, [])
    iex> partial
    :view
    iex> {:ok, ast} = Feel.parse("for i in 1..3 return sum(partial)")
    iex> {:ok, %{ir: {:for, %{partial: partial}, _iterators, _body}}} = Feel.Analysis.Analyzer.analyze(ast, [])
    iex> partial
    true

---

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