# `CEL.Unknown`
[🔗](https://github.com/hansihe/pb_ex/blob/v0.2.0/cel_ex/lib/cel/unknown.ex#L1)

The result of evaluating a CEL expression whose outcome depends on inputs
that are not known, in the spirit of cel-go's `types.Unknown`.

An unknown carries the set of entries it depends on. Each entry pairs an
attribute with the opaque reason the caller supplied:

  * `{:var, name}` — a top-level variable bound to `{:unknown, reason}`.
  * `{:call, function, expr_id}` — a custom function call that returned
    `{:unknown, reason}`.

Bind a variable as unknown by passing `{:unknown, reason}` (or an existing
`CEL.Unknown`, to forward one result into another evaluation):

    {:unknown, unknown} =
      CEL.eval("x < 30 && y > 1", %{x: {:unknown, :timeout}, y: {:unknown, :missing}}, env)

    CEL.Unknown.entries(unknown)
    #=> [{{:var, "x"}, :timeout}, {{:var, "y"}, :missing}]

Operators that can decide their result without an input do so: `false &&
x` is `false` and `true || x` is `true`. Every other operation that reads
an unknown returns an unknown, merging the entries of all unknown operands.
When an operand of a strict operation is an error, the error wins, because
the outcome no longer depends on the unknown inputs. In `&&`, `||` and
comprehensions an unknown wins over an error, because a known input could
still decide the result.

# `attribute`

```elixir
@type attribute() :: {:var, String.t()} | {:call, String.t(), CEL.Checked.expr_id()}
```

# `entry`

```elixir
@type entry() :: {attribute(), reason()}
```

# `reason`

```elixir
@type reason() :: term()
```

# `t`

```elixir
@type t() :: %CEL.Unknown{entries: MapSet.t(entry())}
```

# `attributes`

```elixir
@spec attributes(t()) :: MapSet.t(attribute())
```

Returns the attributes the unknown depends on.

# `entries`

```elixir
@spec entries(t()) :: [entry()]
```

Returns the entries in a stable order.

---

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