# Constraints
Constraints extend Datalog rules beyond simple pattern matching. They appear in
rule bodies alongside relational atoms and filter or extend bindings based on
computed conditions.
## Constraint Types
### Comparison Constraints
Comparison constraints filter bindings. Both `left` and `right` must be bound
before evaluation. The `result` field is `nil`.
| Constructor | Meaning |
|---|---|
| `gt/2` | left > right |
| `lt/2` | left < right |
| `gte/2` | left >= right |
| `lte/2` | left <= right |
| `eq/2` | left == right |
| `neq/2` | left != right |
### Arithmetic Constraints
Arithmetic constraints **bind** a result variable. `left` and `right` must be
bound; after evaluation, `result` is added to the binding environment. All
arithmetic is integer-only. Division by zero filters the binding.
| Constructor | Meaning |
|---|---|
| `add/3` | result = left + right |
| `sub/3` | result = left - right |
| `mul/3` | result = left \* right |
| `div/3` | result = div(left, right) |
### Type Predicate Constraints
Unary filters that check the Elixir type of a bound value. `right` and
`result` are `nil`.
| Constructor | Meaning |
|---|---|
| `type_integer/1` | value is an integer |
| `type_binary/1` | value is a binary (string) |
| `type_atom/1` | value is an atom |
### String Predicate Constraints
Binary filters for string operations. Both operands must be bound and resolve
to binaries. Returns `:filter` if either operand is unbound or not a binary.
| Constructor | Meaning |
|---|---|
| `starts_with/2` | String.starts_with?(left, right) |
| `contains/2` | String.contains?(left, right) |
### Membership Constraints
Tests whether a value is in a constant list. `left` must be bound; `right`
must be a constant list `{:const, [values]}`.
| Constructor | Meaning |
|---|---|
| `member/2` | left in right (list) |
## Evaluation
All constraints are evaluated through `ExDatalog.Constraint.evaluate/3`, which
dispatches to the appropriate module based on the constraint's `op` field. The
dispatch table is closed — adding a new constraint type requires editing the
`constraint_module/1` function in `ExDatalog.Constraint`.
The evaluation context (`ExDatalog.Constraint.Context`) carries storage
backend capabilities. For v0.2.0, no constraint implementation reads from it,
but the plumbing is complete for future use.
## Terms
Constraints use IR terms for their operands:
- `{:var, "X"}` — a variable, looked up in the binding
- `{:const, {:int, 42}}` — a constant integer
- `{:const, {:atom, :alice}}` — a constant atom
- `{:const, {:str, "hello"}}` — a constant string
- `:wildcard` — matches any value without binding