Pi-forall but with some
chickentheorem-proving baked inside.
Chicken-pi is a toy proof assistant based on pi-forall. More precisely, it is based on pi-forall version 2, extended with Coq's inductive types, pattern matching and universes.
All dependencies are defined in the cabal file, and stack should be able to install them for you.
# Clone this repository
git clone https://github.com/Ef55/chicken-pi chicken-pi
# Move to the root of the repository
cd chicken-pi
# Build chicken-pi
stack build
# Run the tests
stack test
# Run a specific file (e.g. pi/Data/List.pi)
stack run chicken-pi pi/Data/List.piIf you are using nix, you can use the provided flake to install all of the dependencies (note however that the flake is not setup to build the project: it just offers a devshell):
# From within this repository
nix develop
# And everything should be set up!
stack testThis project inherited pi-forall's codebase, and did not change much in term of code organization:
src/contains the source of the type-checker:Syntax.hsdefines the syntax of the language.Environment.hsdefines the type-checking context, e.g. which definitions are in scope, and more generally the "type-checking monad" (TcMonad) which is used extensively in the two next files.Equal.hsdefines a reduction from terms into their weak head normal form (whnf), which is used to determines whether two terms are equal, i.e. theequatefunction.TypeCheck.hs, which definescheckTypeandinferType, whose names are pretty self-explanatory.
picontains the embryo of a standard library for chicken-pi (inpi/Dataandpi/Logic) as well as some extra examples (inpi/Examples).testcontains unit tests, as well a runner which type-checks all of these tests (and checks that the type-checking either succeeds or fails, depending on the test case) as well as the files in thepidirectory. Tests suffixed with[✔]are positive tests (i.e. files which should be accepted by the type-checker), and the ones suffixed with[✘]are negative tests (i.e. files which should be rejected by the type-checker).
The language is based on pi-forall (version 2, which doesn't include (ir)relevance and datatypes) and its codebase. The changes/additions can be summarized as follows:
- Addition of (dependent) datatypes and (dependent) pattern matching;
- Addition of a hierarchy of universes;
- Restriction of recursive functions to prevent non-termination. These changes should hopefully make chicken-pi (logically) sound. Note that we did not change pi-forall's syntax to be closer to Coq.
We now detail theses points some more.
Chicken-pi's datatypes should work exactly like the ones from Coq, except for the absence of inference/heuristics and different keywords.
- Parameters and indices are supported.
- They are dependent; consider the following datatype:
any
data D (t1: T1) ... (ti: Ti): I1 -> ... -> Ij -> S C (p1: P1) ... (pk: Pk): S i1 ... ijt_is in the scope of any subsequentT_, as well as in the scope of allI_andP_. Anyp_is also in the scope of any subsequentp_. - Uniform type parameters are not supported.
- Dependent pattern matching is implemented using the
as,in, andreturnkeywords. Take a look atpi/Data/Vect.pi,pi/Data/HList.pi, andpi/Data/Sigma.pifor examples. - Pattern matching must be exhaustive, and all patterns must occur in the same order as the constructors were defined.
- Note that no type inference is attempted on pattern matching; the type must be
known, i.e. using either the top-level signature, annotations or the
returnkeyword.- The previous point makes it so that, if pattern matching occurs in a type
(which includes propositions), it should most likely be annotated with
returnin order to for subsequent usages to type-check.
- The previous point makes it so that, if pattern matching occurs in a type
(which includes propositions), it should most likely be annotated with
In order to avoid paradoxes (e.g. Hurken's
paradox), Type cannot
have type Type.
Instead, types have a level, and Type i has type Type (i + 1); these are
called sorts.
Following Coq, there are two special sorts, Prop and Set.
Sorts are related by a subtyping relation, noted <.
- For any
i,Type i < Type (i + 1). Prop < Type 1andSet < Type 1.- The universes are cumulative, i.e.
t : SandS < S'implyt: S'. - An interesting difference between Coq the proof assistant and its
documentation is the relation between
PropandSet: in the former, the two are unrelated; however, in the later,Prop < Set. Chicken-pi implemented the later. - Related to universes: chicken-pi implements proof irrelevance:
- Terms of sort
Propcould be "eliminated" from terms of sortSetwithout compromising their reduction.- This is implemented, following Coq, by preventing pattern matching on
Propreturning something inSet. - There is one exception: (sub-)singleton elimination, which is supported by
chicken-pi (see
pi/Logic/Eq.piandpi/Examples/Contra.pi).
- This is implemented, following Coq, by preventing pattern matching on
- Terms of sort
- Unlike Coq,
Typehave an explicit level, rather than all occurences of it being fresh variables with universe constrains which must later be solved.
General recursion is disallowed. Instead, a fix construct is available.
The syntax is as follows:
fix self p1 ... pk [r]. body
selfbinds the function itself, thep_s are arbitrary parameters,ris the parameter on which the function will recurse.selfmust be fully applied (i.e. tok + 1arguments) every time it occurs inbody.- The last argument to the recursive calls in
bodymust be "smaller" thanr. A termtis smaller thanrif:- It is a recursive-component of
r. A recursive-component ofris any variables introduced by pattern matching on:r; or another recursive-component ofr.- The variable must bind a recursive-component of the constructor.
- We say that a parameter
p: Pof a constructor for typeDis a recursive-component of the constructor ifDoccurs inP. - See
test/Fix/NonRecursiveComponent.pifor an example of non-recursive-component.
- It is of the form
l rwherelis itself smaller thanr. - It is of the form
\x . bwherebis itself smaller thanr.
- It is a recursive-component of
Also known as "acknowledgment of unsupported features".
The following should require fairly minimal changes, or changes which are not too involved:
- Change the syntax to be closer to Coq:
case v of C -> ...↦match v with C => ...someF : T -> U; someF = \t . ...↦Definition someF (t: T): U := ...- etc.
- Support uniform type parameters;
- Support
if-then-else; - Relax the "smaller" relation;
- Remove the
=,Refl,subst, andcontrabuiltins. The language can already encode them (see Eq.pi and Contra.pi);
Some more advanced feature of Coq which are not supported are:
- Support universe polymorphism;
- Better patterns (relax ordering, top-level wildcard/default case, nested patterns, etc.); this might require/justify moving to an elaboration approach;
- Add co-inductive types;
- Support implicit parameters;
- Add Typeclasses.