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

The type of the result of a call of a built-in function, exact to the values of its arguments (D-161, step C).

`Feel.Analysis.Calls.result_type/3` gives a call the types that the signatures of the function say (the kinds of the result
and `Null`). That is true and not exact: `not(b)` for a `b` that is `true` is `false`, `string length(s)` for a `s` in
`{"a", "b"}` is `1`, `abs(n)` for an `n` in `[-5..3]` is `[0..5]`, and none of them is `null` unless an argument is. A
**family** of rules (a module under `Feel.Analysis.Images`) says that, for the functions it names, from the types of the
arguments:

    @behaviour Feel.Analysis.Images

    def names, do: ["not"]
    def image("not", [argument]), do: {:ok, ...}

`image/2` gives the whole type of the result, `Null` included, or `:none` for arguments the family has no rule for, and the
signatures answer. A rule is a claim about the run, so it is checked against it: `Feel.ImageCheck` (`test/support`) runs the
function on the values at the edges of the types of the arguments (`Feel.Type.Witness.edges/2`) and holds the result to the
rule. **Every value the run gives is in the type, and a `null` that the type has is one that some arguments give**: the first
is soundness (a type that is too small is a wrong answer, D-159), the second is that a `null` is in a type only if a value can
cause it (D-161).

The arguments are the types of the call as it is analyzed (`Feel.IR.type/1`: with the sets of values), in the order of the
parameters, and only the ones that are given (an optional parameter that is left out is not in the list). A rule is not asked
for a call that an extension may answer, whose function is not the one the rule is for.

## What a rule does about `null`

The run gives `null` for a `null` argument, for an argument of a kind the function does not take (with an error), and for the
values of the right kinds that the function has no result for. `with_null/2` adds `Null` for the first, and the rule says the
others: a `null` that is not in the type of the result has to be one that no value of the arguments causes. A function that
takes `null` as it takes any other value (`is`, `string(null)`, `get or else`) says so in its rule.

## Adding a family

A family is a module that has the behaviour, listed in `@families` below. It names the functions it has rules for, and gives
`image/2` a clause for each, and a catch-all that is `:none`. Its test is a grid of argument types for each function, held
to the run with `Feel.ImageCheck.check!/3`.

# `image`

```elixir
@callback image(String.t(), [Feel.Type.Union.t()]) :: {:ok, Feel.Type.Union.t()} | :none
```

The type of the result of a call, for the types of its arguments, or `:none`.

# `names`

```elixir
@callback names() :: [String.t()]
```

The names of the functions the family has rules for.

# `families`

```elixir
@spec families() :: [module()]
```

The families, in the order they are asked.

# `image`

```elixir
@spec image(String.t(), [Feel.Type.Union.t()]) :: {:ok, Feel.Type.Union.t()} | :none
```

The type of the result of a call of the built-in function `name` for the types of its arguments, if a family has a rule for
it.

    iex> Feel.Analysis.Images.image("not", [[{:boolean, true}]]) |> elem(1) |> Feel.Type.Union.format()
    "boolean = false"
    iex> Feel.Analysis.Images.image("no such function", [[:number]])
    :none
    iex> Feel.Analysis.Images.image("abs", [[{:number, Feel.Type.NumberSet.interval(Decimal.new(-5), Decimal.new(3))}]]) |> elem(1) |> Feel.Type.Union.format()
    "number in [0..5]"

# `with_null`

```elixir
@spec with_null([Feel.Type.Union.t()], Feel.Type.Union.t()) :: Feel.Type.Union.t()
```

The type of a result with `Null` added when an argument can be `null`, which a call of a function that does not take `null`
gives `null` for.

    iex> Feel.Analysis.Images.with_null([[:number], [:number, :null]], [:boolean])
    [:boolean, :null]
    iex> Feel.Analysis.Images.with_null([[:number]], [:boolean])
    [:boolean]

---

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