Theoria theorem modules are ordinary Elixir modules that use Theoria.DSL and declare checked theorem functions with the theorem macro.
defmodule MyApp.Proofs do
use Theoria.DSL
theorem :true_is_true do
type do
const(:True)
end
proof do
const(:true_intro)
end
end
endFor each theorem, the macro generates three documented functions:
<name>_type/0returns unelaborated type syntax.<name>_proof/0returns unelaborated proof syntax.<name>_theorem/1elaborates and checks the theorem against an environment.
Theorems may be universe-polymorphic:
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
endThe macro also registers theorem names through __theoria_theorems__/0, which lets tooling check a whole module:
{: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:
{:ok, env} = Theoria.Prelude.env()
{:ok, env, theorems} = Theoria.Theorem.add_all_to_env(MyApp.Proofs, env)A checked theorem's trusted assumptions can be inspected with:
{:ok, axioms} = Theoria.Theorem.axioms(env, theorem)From Mix, use:
mix theoria.theorems MyApp.Proofs
mix theoria.theorems --install MyApp.Proofs
mix theoria.theorems --axioms MyApp.Proofs
mix theoria.validate --only logic
mix theoria.theorems checks theorem modules against Theoria.Prelude.env/0. 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.
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.
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:
term do
and_intro(q, p, and_right(p, q, h), and_left(p, q, h))
endThe quote DSL also supports binder and helper forms:
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
endGenerator code can splice pre-built syntax and universe levels with ^:
u = Theoria.Level.param(:u)
nat = Theoria.Syntax.const(:Nat)
term do
forall :a, sort(^u) do
^nat ~> a
end
endBecause 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:
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()
endbool() 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.