# `ExDatalog.Term`
[🔗](https://github.com/thanos/ex_datalog/blob/v0.5.0/lib/ex_datalog/term.ex#L1)

Term types used in Datalog atom arguments.

A term is one of:

- A logic variable: `{:var, name}` — matches any value and binds it to `name`.
- A constant: `{:const, value}` — a ground value (integer, string, or atom).
- A wildcard: `:wildcard` — an anonymous variable that matches any value without binding.

## Examples

    iex> ExDatalog.Term.var("X")
    {:var, "X"}

    iex> ExDatalog.Term.const(:alice)
    {:const, :alice}

    iex> ExDatalog.Term.const(42)
    {:const, 42}

    iex> ExDatalog.Term.wildcard()
    :wildcard

# `shorthand`

```elixir
@type shorthand() :: atom() | integer() | String.t() | list() | t()
```

# `t`

```elixir
@type t() :: {:var, var_name()} | {:const, value()} | :wildcard
```

# `value`

```elixir
@type value() :: integer() | String.t() | atom() | list()
```

# `var_name`

```elixir
@type var_name() :: String.t()
```

# `const`

```elixir
@spec const(value()) :: {:const, value()}
```

Constructs a constant term.

Accepts integers, strings, and atoms. Floats are not supported — Datalog
relations use discrete values. If you pass a float, `const/1` raises
`ArgumentError`.

Note that `true`, `false`, and `nil` are valid Elixir atoms and are
accepted as constants, producing `{:const, true}`, `{:const, false}`,
and `{:const, nil}` respectively. Use these with care — `nil` in
particular may be confused with an absent value downstream.

## Examples

    iex> ExDatalog.Term.const(:alice)
    {:const, :alice}

    iex> ExDatalog.Term.const(42)
    {:const, 42}

    iex> ExDatalog.Term.const("hello")
    {:const, "hello"}

# `const?`

```elixir
@spec const?(t()) :: boolean()
```

Returns `true` if the term is a constant.

## Examples

    iex> ExDatalog.Term.const?({:const, :alice})
    true

    iex> ExDatalog.Term.const?({:var, "X"})
    false

    iex> ExDatalog.Term.const?(:wildcard)
    false

# `from`

```elixir
@spec from(shorthand()) :: t()
```

Converts a shorthand value to a term.

Follows Prolog convention for distinguishing variables from constants:

- **Uppercase atoms** become logic variables: `:A` → `{:var, "A"}`,
  `:Pkg` → `{:var, "Pkg"}`
- **`:_`** becomes a wildcard: `:_` → `:wildcard`
- **Lowercase atoms** become constants: `:alice` → `{:const, :alice}`
- **Integers** become constants: `42` → `{:const, 42}`
- **Strings** become constants: `"hello"` → `{:const, "hello"}`
- **Lists** become constants: `[:a, :b]` → `{:const, [:a, :b]}`
- **Existing terms** pass through unchanged

This is the inverse of writing out `Term.var/1`, `Term.const/1`, and
`Term.wildcard/0` explicitly, and is designed for use with the
tuple-shorthand forms of `Program.add_rule/3` and `Program.add_rule/4`.

## Examples

    iex> ExDatalog.Term.from(:A)
    {:var, "A"}

    iex> ExDatalog.Term.from(:Pkg)
    {:var, "Pkg"}

    iex> ExDatalog.Term.from(:_)
    :wildcard

    iex> ExDatalog.Term.from(:alice)
    {:const, :alice}

    iex> ExDatalog.Term.from(42)
    {:const, 42}

    iex> ExDatalog.Term.from("hello")
    {:const, "hello"}

    iex> ExDatalog.Term.from([:a, :b])
    {:const, [:a, :b]}

    iex> ExDatalog.Term.from({:var, "X"})
    {:var, "X"}

    iex> ExDatalog.Term.from({:const, :ok})
    {:const, :ok}

    iex> ExDatalog.Term.from(:wildcard)
    :wildcard

# `valid?`

```elixir
@spec valid?(term()) :: boolean()
```

Returns `true` if the term is a valid `ExDatalog.Term.t()`.

## Examples

    iex> ExDatalog.Term.valid?({:var, "X"})
    true

    iex> ExDatalog.Term.valid?({:const, 42})
    true

    iex> ExDatalog.Term.valid?(:wildcard)
    true

    iex> ExDatalog.Term.valid?(:bad)
    false

# `var`

```elixir
@spec var(var_name()) :: {:var, var_name()}
```

Constructs a logic variable term.

## Examples

    iex> ExDatalog.Term.var("X")
    {:var, "X"}

    iex> ExDatalog.Term.var("ParentNode")
    {:var, "ParentNode"}

# `var?`

```elixir
@spec var?(t()) :: boolean()
```

Returns `true` if the term is a logic variable.

## Examples

    iex> ExDatalog.Term.var?({:var, "X"})
    true

    iex> ExDatalog.Term.var?({:const, :alice})
    false

    iex> ExDatalog.Term.var?(:wildcard)
    false

# `variables`

```elixir
@spec variables([t()]) :: [var_name()]
```

Returns all variable names present in a list of terms.

## Examples

    iex> ExDatalog.Term.variables([{:var, "X"}, {:const, :alice}, {:var, "Y"}, :wildcard])
    ["X", "Y"]

# `wildcard`

```elixir
@spec wildcard() :: :wildcard
```

Constructs an anonymous wildcard term.

A wildcard matches any value but does not bind it to a name.
Wildcards may appear in rule bodies but not in rule heads.

## Examples

    iex> ExDatalog.Term.wildcard()
    :wildcard

# `wildcard?`

```elixir
@spec wildcard?(t()) :: boolean()
```

Returns `true` if the term is a wildcard.

## Examples

    iex> ExDatalog.Term.wildcard?(:wildcard)
    true

    iex> ExDatalog.Term.wildcard?({:var, "X"})
    false

---

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