# Theorem Modules
Theoria theorem modules are ordinary Elixir modules that `use Theoria.DSL` and declare checked theorem functions with the `theorem` macro. See `examples/theorem_module/run.exs` for a small runnable workflow.
```elixir
defmodule MyApp.Proofs do
use Theoria.DSL
theorem :true_is_true do
type do
const(:True)
end
proof do
const(:true_intro)
end
end
end
```
For each theorem, the macro generates three documented functions:
- `<name>_type/0` returns unelaborated type syntax.
- `<name>_proof/0` returns unelaborated proof syntax.
- `<name>_theorem/1` elaborates and checks the theorem against an environment.
Theorems may be universe-polymorphic:
```elixir
theorem :identity, universes: [:u] do
type do
term do
forall :a, sort(u) do
a ~> a
end
end
end
proof do
term do
lam :a, sort(u) do
lam :x, a do
x
end
end
end
end
end
```
The macro also registers theorem names through `__theoria_theorems__/0`, which lets tooling check a whole module:
```elixir
{:ok, env} = Theoria.Prelude.env()
{:ok, theorems} = Theoria.Theorem.check_all(MyApp.Proofs, env)
```
Checked theorems can also be installed into an environment as opaque theorem declarations. This lets later theorems refer to earlier theorem constants without making proofs unfold during normalization:
```elixir
defmodule MyApp.DependentProofs do
use Theoria.DSL
theorem :identity do
type do
forall :a, type(0) do
forall :x, var(:a) do
var(:a)
end
end
end
proof do
lam :a, type(0) do
lam :x, var(:a) do
var(:x)
end
end
end
end
theorem :identity_again do
type do
forall :a, type(0) do
forall :x, var(:a) do
var(:a)
end
end
end
proof do
const(:identity)
end
end
end
{:ok, env} = Theoria.Prelude.env()
{:ok, env, theorems} = Theoria.Theorem.add_all_to_env(MyApp.DependentProofs, env)
```
Checking `identity_again` independently fails because `:identity` is not in the environment yet. Sequential installation succeeds because each checked theorem is installed before the next theorem is elaborated.
A checked theorem's trusted assumptions can be inspected with:
```elixir
{:ok, axioms} = Theoria.Theorem.axioms(env, theorem)
```
From Mix, use:
```bash
mix theoria.theorems MyApp.Proofs
mix theoria.theorems --install MyApp.Proofs
mix theoria.theorems --axioms MyApp.Proofs
mix theoria.theorems --json --install MyApp.Proofs
mix theoria.validate --only logic
```
`mix theoria.theorems` checks theorem modules against `Theoria.Prelude.env/0`. Named downstream modules are loaded directly from the project code path. With `--install`, theorem modules are checked sequentially and installed as opaque theorem declarations, so later theorems/modules can refer to earlier theorem constants. With `--axioms`, the task reports trusted axiom assumptions used by each theorem module. With `--json`, the task emits a `Theoria.Theorem.Report` encoded by Jason for downstream automation.
`mix theoria.check` runs the full native validation corpus, including theorem modules, definitional-equality checks, and inductive specs. Use `mix theoria.validate --only CATEGORY` to narrow validation while developing.
## Common failures
- `unknown constant: name` means the proof references a declaration that is not in the current environment. If a theorem depends on an earlier theorem from the same module, run the Mix task with `--install` or call `Theoria.Theorem.add_all_to_env/2` so checked theorems are installed before later proofs are elaborated.
- A module-loading error from `mix theoria.theorems MyApp.Proofs` usually means the module has not been compiled or is not on the project code path. Compile the downstream project first, or pass the module name exactly as Elixir knows it.
- Custom constants must be installed into the environment before theorem checking. `Theoria.Prelude.env/0` only provides Theoria's built-in libraries.
- Type/proof mismatch errors come from the native kernel: the elaborated proof term did not check against the declared theorem type.
The generated theorem functions are intentionally normal Elixir functions so ExDoc can document them alongside their surrounding module docs.
## Quoted term DSL
Inside `term do ... end`, bare lowercase names become named variables and function calls become constant applications:
```elixir
term do
and_intro(q, p, and_right(p, q, h), and_left(p, q, h))
end
```
The quote DSL also supports binder and helper forms:
```elixir
term do
forall :p, prop() do
p ~> p
end
end
term do
lam :f, p ~> q do
lam :x, p do
let :result, q, app(f, x) do
result
end
end
end
end
```
Generator code can splice pre-built syntax and universe levels with `^`:
```elixir
u = Theoria.Level.param(:u)
nat = Theoria.Syntax.const(:Nat)
term do
forall :a, sort(^u) do
^nat ~> a
end
end
```
Because `and`, `or`, and `not` are reserved Elixir words, theorem code should use the readable aliases `conj(p, q)` and `neg(p)` for the object-language constants `:and` and `:not`.
The quote DSL also provides aliases for constants that are awkward or ambiguous in Elixir syntax:
```elixir
term do
eq(bool(), bool_not(bool_true()), bool_false())
end
term do
forall :n, nat() do
eq(nat(), nat_add(zero, n), n)
end
end
term do
true_prop() ~> false_prop()
end
```
`bool()` and `nat()` refer to computational types. `bool_true()` and `bool_false()` refer to computational Bool constructors. `true_prop()` and `false_prop()` refer to logical propositions `True` and `False`.
If unsupported Elixir syntax appears inside a term block, the DSL raises targeted errors for common mistakes such as lists, tuples, strings, numbers, malformed binders, and uppercase `Bool`/`Nat`/`List` aliases.