File structure and imports
An Abella development is a collection of plain text files. Two of them describe the object system (the specification) and the rest record definitions and proofs about it.
Source files
| Suffix | Purpose |
|---|---|
.sig | The signature: kinds, constants, and predicates. |
.mod | The clauses of a specification, written in the specification logic. |
.thm | A development: declarations, definitions, theorems, and proofs. |
.thc | A compiled .thm file, produced automatically or with -c. |
The .sig and .mod files share a base name. A specification named eval
is the pair eval.sig and eval.mod. The .thm file that reasons about it
uses the same base name by convention but need not.
Signatures
A signature begins with sig followed by its name and ends with .:
sig eval.
kind tm, ty type.
type app tm -> tm -> tm.
type abs (tm -> tm) -> tm.
type arrow ty -> ty -> ty.
type of tm -> ty -> o.
type eval, step, nstep tm -> tm -> o.
kind introduces atomic types and their arity. type introduces constants
and gives their types. A constant whose target type is o is a predicate of
the specification logic. See
Specification logic for the full syntax.
A signature may build on other signatures with accum_sig:
sig eval.
accum_sig terms.
type eval tm -> tm -> o.
The named signature is read first, and its declarations become part of the
current signature. A signature is flattened in dependency order, so
accum_sig chains are allowed. Cycles are rejected.
Modules
A module begins with module followed by its name and contains clauses:
module eval.
of (abs R) (arrow T U) :- pi x\ (of x T => of (R x) U).
of (app M N) T :- of M (arrow U T), of N U.
eval (abs R) (abs R).
eval (app M N) V :- eval M (abs R), eval (R N) V.
A module may include the clauses of other modules with accumulate:
module eval.
accumulate terms.
If a module accumulates another module, its signature must accum_sig the
other module's signature. This restriction ensures that every constant used
by the accumulated clauses is declared in the importing signature. See
Specification logic for details.
Developments
A .thm file is a sequence of top-level commands. The two commands that
connect a development to its specification are Specification and Import.
Specification
Specification "name". reads the signature and module with the given base
name. It must be the first command in a development, because the logic is
parameterized by the specification:
Specification "eval".
The extension is added automatically: Abella looks for eval.sig and
eval.mod. The name may include a relative path, and the path is resolved
relative to the directory of the .thm file (or the current directory in
interactive mode).
Specification may be used only once. If a development needs declarations
from several specifications, combine them with accum_sig and accumulate
instead.
Import
Import "name". loads a previously compiled development. The extension
.thc is added automatically:
Import "util".
Importing makes the definitions and theorems of the compiled file available
without rechecking its proofs. If the .thc file is missing or older than
the corresponding .thm file, Abella recompiles it before importing.
The importing development must be compatible with the imported one:
- every kind and constant mentioned by the imported file must already exist in the importing development;
- every specification clause used by the imported file must already be present;
- the clauses of a predicate declared in the imported file cannot be extended by the importing development.
Import also accepts a with clause that renames predicates. The syntax is:
Import "name" with p = q, r = s.
Each replacement maps a predicate declared in the imported development to a predicate of the importing development. The replacements must be pairwise distinct.
Recursive compilation
By default, importing a .thm file compiles it and any of its imports that
are out of date. The -N (or --non-recursive) option disables this
recursion:
$ abella --non-recursive foo.thm
With -N, Abella assumes that every imported .thc file is current and
fails if one is missing.
Default compiled output
In batch mode, compiling file.thm writes file.thc next to it. The
-c option overrides the output path:
$ abella -c build/foo.thc foo.thm
In interactive mode the compiled development is not written to disk.
Naming rules
The names of types, constants, predicates, variables, and theorems follow the same lexical rules:
- a name begins with a letter, or one of the symbols
-,=,^,`,',?,$; - the rest may also contain digits and the symbols
_,/,*,@,+,#,!,~.
Names beginning with an uppercase letter are variables in formulas unless they are bound. Lowercase names are usually constants or predicates, but the distinction is enforced by binding structure rather than by case.
Nominal constants displayed by Abella have the form n1, n2, and so on.
They are generated by the system, so source files normally refer to them
only indirectly through nabla binders.
Directory layout
There is no required layout. The examples shipped with Abella group related files in directories:
examples/
lambda-calculus/
eval.sig
eval.mod
eval.thm
type-uniq/
type-uniq.sig
type-uniq.mod
type-uniq.thm
logic/
...
A relative name is resolved against the directory of the importing file.
Absolute names are used as they are. The Set load_path option records a
load path, but 2.0.8 does not fall back to it when a relative name is not
found:
Set load_path "lib".
Specification "eval".
To read a specification from another directory, write the directory as part of the name:
Specification "lib/eval".
Generated documentation
abella_doc reads .thm, .sig, and .mod files and writes HTML pages
beside them. For each file.thm it produces file.html and, for each
specification, file.lp.html, together with JSON files that carry the
annotations used by the generated pages. These outputs are generated
artifacts and should not be edited by hand. See
abella_doc.
abella_dep reads the same source files and writes a Makefile that records
the dependencies between them. See abella_dep.