This part is meant as a brief, but complete reference to Tutch.
The proof checker Tutch is invoked by
$ /afs/andrew/scs/cs/15-399/bin/tutch [options] [files]
The files are extended by `.tut' if they do not have an extension already. Options are:
Assignments submission is possible via
$ /afs/andrew/scs/cs/15-399/bin/submit -r file [options] [files]
Options are the same as for tutch, but -r is mandatory. The status of a submission can be checked via
$ /afs/andrew/scs/cs/15-399/bin/status file
This retrieves the status of the submission file handed in via submit -r file ....
Tutch recognizes a set of special symbols. They do not have to be separated by spaces from the remaining code, but serve as separators themselves. These symbols are
( ) [ ] ; : = ~ & | => <=>
Furthermore there are reserved words which cannot be used as identifiers:
T F proof begin end
Identifiers are made up of letters `a-zA-Z', digits `0-9' underscores `_' and primes `''.
Atoms Q are identifiers that start with capital letter. Propositions A, B have the following grammar
A, B ::= T % Truth
| F % Falsehood
| Q % Atom
| ~A % Negation
| A & B % Conjunction
| A | B % Disjunction
| A => B % Implication
| A <=> B % Equivalence
| (A) % Parentheses
The binary operators `&', `|' and `=>' are right associative, `<=>' is non-associative. Binding strength decreases in this order:
~ & | => <=>
A hypothesis H is just a proposition. A proof entry E is either a line or a frame. A proof P is a non-empty list of entries.
H ::= A % Hypothesis
E ::= A % Line
| [ H; P ] % Frame
P ::= E % Final step
| E; P % Step and remaining proof
A proof name x is a non-capital identifier. A Tutch file F is a sequence of proof declarations. A proof declaration D has the following syntax:
D ::= proof x: A = begin P end % Proof of A with name x
F ::= % Empty file
| D; F % Declaration and remaining file
We extend our list of special symbols and reserved words by the following:
, annotated term fst snd inl inr case of fn abort
Proof terms for propositional logic are formed according to the following grammar:
M, N ::= x % Variable
| (M, N) % Pair
| fst M % First projection
| snd M % Second projection
| inl M % Left injection
| inr M % Right injection
| case M of inl x => N | inr y => O end % Case analysis
| fn x => M % Abstraction
| M N % Application
| () % Empty tuple (proof of truth)
| abort M % Falsehood elimination
| M : A % Annotation
Application is a "invisible" left-associative infix operator. It has maximal binding strength, along with the prefix operators `fst', `snd', `inl', `inr', `abort'. This enforces use of parentheses in most cases. E.g.,
(fst x) ((snd x) y)
has already a minimum amount of parentheses. Abstraction `fn x =>' binds less than application and annotation `:' least. The following term is syntactically correct.
fn y => fn x => x y : A => (A => B) => B
Annotated proofs P are proofs as defined above annotated with proof terms. This changes the syntax of hypotheses H and proof entries E.
H ::= x : A % Hypothesis
E ::= M : A % Line
| [ H; P ] % Frame
P ::= E % Final step
| E; P % Step and remaining proof
A Tutch file F now can contain proof, term and annotated proof declarations D:
D ::= proof ...
| annotated proof x: A = begin P end % Annotated proof of A with name x
| term x: A = M % Proof of A with name x
F ::= % Empty file
| D; F % Declaration and remaining file
New special symbols and keywords are:
* + -> :: nat bool list 0 s rec true false if then else nil val
Types T, T' have the following grammar:
T, T' ::= 1 % Unit type
| 0 % Empty type
| a % Atom
| nat % Natural numbers
| bool % Booleans
| T list % Lists of element type T
| T * T' % Product
| T + T' % Disjoint sum
| T -> T' % Function space
| (T) % Parentheses
`list' is a postfix operator.
The binary operators `*', `+' and `=>' are right associative. Binding strength decreases in this order:
list * + ->
We extend the grammar for terms by the following constructs:
M, N ::= ...
| 0 % Zero
| s M % Successor
| rec M of f 0 => N | f (s x) => O end % Recursion over nat
| true % True
| false % False
| if M then N else O % Boolean case distinction
| nil % Empty list
| M :: N % List construction
| rec M of f nil => N | f (x :: xs) => O end % Recursion over list
`0', `true', `false' and `nil' are constants, `s' and `if r then s else' are prefix operators and `::' is an infix operator with lower precedence than the prefix operators or application.
We add one new declaration to the syntax of tutch files:
D ::= ...
| val x: T = M % Program of type T with name x
F ::= % Empty file
| D; F % Declaration and remaining file
Reasoning in First-Order Logic (FOL) requires handling of universally and existentially quantified propositions. New special symbols are
! ? .
We extend our definition of propositions by
A, B ::= ...
| R M1...Mn % Instantiation
| !x:T. A % Universal quantification
| ?x:T. A % Existential quantification
Relation symbols R are capital identifiers. Only they can be instantiated by terms Mi, e.g. `A(x)', which is the same as `A x'. Instantiation binds strongest, as strong as application and the prefix operators for terms M.
Quantification `!x:T' resp. `?x:T. A' is treated as a prefix operator with minimal precedence (like lambda abstraction). Ordered by binding strength, the operators that appear in propositions are:
!x:T. resp. ?x:T., <=>, =>, |, &, ~, instantiation
The `proof' declaration supports now also proofs in FOL. Two judgments can form a statement of the proof: an assertion A (representing `A true' and a term declaration M : T expressing "M has type T". In the same way there are now two forms of hypotheses: x : T, which introduces a new parameter x into the proof, and A which assumes that A is true. Furthermore one frame can introduce several hypotheses, separated by commas. The grammar for proofs is the following:
H ::= A % Hypothesis introduction
| x : T % Parameter introduction
Hs ::= H % Last hypothesis
| H, Hs % Several hypotheses
E ::= A % Line: Assertion
| M : T % Line: Term declaration
| [ Hs; P ] % Frame
P ::= E % Final step
| E; P % Step and remaining proof
All variables in a proposition that appears in a proof must be bound by quantifiers or be (visible) parameters introduced by frames.
We add the two binary relations "less than" and "equal to" to our definition of propositions
A, B ::= ...
| M < N % M less than N
| M = N % M equal to N
These relations allow us to prove properties about them and defined functions by induction.
Unfortunately, `=' introduces a ambiguity into our syntax, e.g. in
proof Ex2 : !x:nat. 0 < x => ?y:nat. s(y) = x = ...
While parsing the first `=', it is not clear whether it marks the end of the proposition or stands for the equality relation. This ambiguity is resolved by the following rule:
Whenever the expression before `=' is definitively a term, then `=' is parsed as equality. In all other cases it is parsed as the end of the declaration.
In our case `s(y)' is definitively a term. At the next `=', the expression on the left of it is `s(y)=x', which is a proposition, not a term. Thus the end of the declaration is correctly recognized. The same happens in the following example:
val nth : nat -> tau list -> tau -> tau = ...
The expression `tau' left of the equality symbol is a variable. It could be a term or a type variable. Thus it is not definitely a term, and the parser finished parsing the type of `nth' here.
Not correctly resolved is the ambiguity in this case:
proof refl : !x:nat. x = x = ...
Since `x' is either a term variable or a type variable from the perspective of mere syntax, it is not definitively a term. Thus the parser detects falsely the end of the declaration of `refl'. The parser will then try to interpret `!x:nat.x' as a proposition, and fail with the following error message:
Category mismatch: x is a variable, but a proposition is expected in this place
To work around this bug, insert parentheses somewhere around the equality expression, e.g.
proof refl : !x:nat. (x = x) = ...
The introduction and elimination rules for equality and less-than give rise to the following proof terms. All are reserved words:
eq0 eqS eqE0S eqES0 eqESS less0 lessS lessE0 lessES
Of these, two are constants: eq0 and less0. All other are prefix operators. For induction we reuse the `rec' construct for primitive recursion.
We reuse `=' for equality on lists. The following proof terms represent the introduction and elimination rules for equality on lists. These are new reserved words:
eqN eqC eqENC eqECN eqECC
Except eqN, which is a constants, all are prefix operators. The rule for eqC is:
If M : xs = ys, then eqC M : x::xs = x::ys for an arbitrary x.
Here we assume that all these lists xs, ys, x::xs, x::ys are well-formed and of the same type.
This sections summarizes the syntax specification given in the previous sections.
Special Symbols:
( ) [ ] ; : = ~ & | => <=> , * + -> :: ! ? . <
Reserved words:
annotated proof term val begin end T F nat bool list inl inr case of fst snd fn abort 0 s rec true false if then else nil eq0 eqS eqE0S eqES0 eqESS less0 lessS lessE0 lessES eqN eqC eqENC eqECN eqECC
Proposition expressions:
A, B ::= T % Truth
| F % Falsehood
| Q % Atom
| ~A % Negation
| A & B % Conjunction
| A | B % Disjunction
| A => B % Implication
| A <=> B % Equivalence
| R M1...Mn % Instantiation
| !x:T. A % Universal quantification
| ?x:T. A % Existential quantification
| M < N % M less than N
| M = N % M equal to N
Type expressions:
T, T'::= 1 % Unit type
| 0 % Empty type
| a % Atom
| nat % Natural numbers
| bool % Booleans
| T list % Lists of element type T
| T * T' % Product
| T + T' % Disjoint sum
| T -> T' % Function space
Terms:
M, N ::= x % Variable
| (M, N) % Pair
| fst M % First projection
| snd M % Second projection
| inl M % Left injection
| inr M % Right injection
| case M of inl x => N | inr y => O end % Case analysis
| fn x => M % Abstraction
| M N % Application
| () % Empty tuple (proof of truth)
| abort M % Falsehood elimination
| M : A % Annotation
| 0 % Zero
| s M % Successor
| rec M of f 0 => N | f (s x) => O end % Recursion over nat
| true % True
| false % False
| if M then N else O % Boolean case distinction
| nil % Empty list
| M :: N % List construction
| rec M of f nil => N | f (x :: xs) => O end % Recursion over list
| eq0 % Proof of 0 = 0
| eqS M % Proof of M = N |- s M = s N
| eqE0S M % Elimination of 0 = s N
| eqES0 M % Elimination of s M = 0
| eqESS M % Proof of s M = s N |- M = N
| less0 M % Proof of 0 < s M
| lessS M % Proof of M < N |- s M < s N
| lessE0 M % Elimination of s M = 0
| lessES M % Proof of s M = s N |- M = N
| eqN % Proof of nil = nil
| eqC M % Proof of Ms = Ns |- M::Ms = M::Ns
| eqENC M % Elimination of nil = M::Ms
| eqECN M % Elimination of M::Ms = nil
| eqECC M % Proof of M::Ms = N::Ns |- Ms = Ns
Operator precedence:
_ _ (application) list inl inr fst ... (all atomar prefix ops) :: if M then N else let (x,u) = M in fn x => < = ~ & * | + => -> <=> !x:t. ?x:t.
Proofs:
H ::= A % Hypothesis introduction
| x : T % Parameter introduction
Hs ::= H % Last hypothesis
| H, Hs % Several hypotheses
E ::= A % Line: Assertion
| M : T % Line: Term declaration
| [ Hs; P ] % Frame
P ::= E % Final step
| E; P % Step and remaining proof
Annotated Proofs:
H ::= x : A % Hypothesis
E ::= M : A % Line
| [ H; P ] % Frame
P ::= E % Final step
| E; P % Step and remaining proof
Declarations:
D ::= proof x: A = begin P end % Proof of A with name x
| annotated proof x: A = begin P end % Annotated proof of A with name x
| term x: A = M % Proof of A with name x
| val x: T = M % Program of type T with name x
F ::= % Empty file
| D; F % Declaration and remaining file
A requirements file F specifies proof and program tasks, but does not give any proofs or implementations. Grammar:
S ::= proof x: A % Proof specification
| annotated proof x: A % Proof specification
| term x: A % Term specification
| val x: T % Program specification
F ::= % Empty file
| S; F % Specification and remaining file
We give an inductive definition of the proof checking algorithm implemented in Tutch via two judgments `step' and `valid'. The definition is given as in Twelf syntax.
% Tutch proof checker for propositional logic
% any infinite datatype:
nat : type.
z : nat.
s : nat -> nat.
% Propositions
prop : type. %name prop A.
% Formation rules
true : prop.
false : prop.
atom : nat -> prop.
& : prop -> prop -> prop. %infix right 14 &.
| : prop -> prop -> prop. %infix right 13 |.
=> : prop -> prop -> prop. %infix right 12 =>.
% Notational definitions
~ : prop -> prop
= [A:prop] (A => false). %prefix 15 ~.
<=> : prop -> prop -> prop
= [A:prop][B:prop] (A => B) & (B => A) . %infix none 11 <=>.
% One-step inference algorithm
step : prop -> type.
nonhyp : prop -> type. % available non-hypothetical judgment
hyp : prop -> prop -> type. % available hypothetical judgment
% immediate tactic
imm : nonhyp A -> step A.
% introduction tactics
trueI : step true.
&I : nonhyp A -> nonhyp B -> step (A & B).
|IL : nonhyp A -> step (A | B).
|IR : nonhyp B -> step (A | B).
=>I : hyp A B -> step (A => B).
% elimination tactics
falseE : nonhyp false -> step A.
&EL : nonhyp (A & B) -> step A.
&ER : nonhyp (A & B) -> step B.
|E : nonhyp (A | B) -> hyp A C -> hyp B C -> step C.
=>E : nonhyp (A => C) -> nonhyp A -> step C.
% Proofs
proof : type. %name proof P.
final : prop -> proof. % P, Q ::= A
line : prop -> proof -> proof. % | A; P
frame : prop -> proof -> proof -> proof. % | [H; P]; Q
% Proof checking
valid : proof -> prop -> type.
vfinal : step A -> valid (final A) A.
vline : step A -> (nonhyp A -> valid P B) -> valid (line A P) B.
vframe : (nonhyp H -> valid P A) -> (hyp H A -> valid Q B)
-> valid (frame H P Q) B.
Here we give a new Twelf implementation of Tutch that includes proof terms. The definition and the typing rules are:
% Tutch proof checker for propositional logic
% Version 0.2 proof terms
% any infinite datatype:
nat : type.
z : nat.
s : nat -> nat.
% Propositions
prop : type. %name prop A.
% Formation rules
true : prop.
false : prop.
atom : nat -> prop.
& : prop -> prop -> prop. %infix right 14 &.
| : prop -> prop -> prop. %infix right 13 |.
=> : prop -> prop -> prop. %infix right 12 =>.
% Notational definitions
~ : prop -> prop
= [A:prop] (A => false). %prefix 15 ~.
<=> : prop -> prop -> prop
= [A:prop][B:prop] (A => B) & (B => A) . %infix none 11 <=>.
% Proof terms
term : type. %name term M.
fst : term -> term.
snd : term -> term.
, : term -> term -> term. %infix right 14 ,.
inl : term -> term.
inr : term -> term.
case : term -> (term -> term) -> (term -> term) -> term.
\ : (term -> term) -> term. %prefix 11 \.
: term -> term -> term. %infix left 20 .
<> : term.
abort: term -> term.
% Typing judgement
in : term -> prop -> type. %infix none 0 in.
% Typing rules
&I : M in A -> N in B -> (M , N) in A & B.
&EL : M in A & B -> fst M in A.
&ER : M in A & B -> snd M in B.
|IL : M in A -> inl M in A | B.
|IR : M in B -> inr M in A | B.
|E : M in A | B -> ({x: term} x in A -> N x in C)
-> ({y: term} y in B -> L y in C)
-> case M N L in C.
=>I : ({x: term} x in A -> M x in B) -> \ M in A => B.
=>E : M in A => B -> N in A -> M N in B.
trueI : <> in true.
falseE: M in false -> abort M in C.
We add annotated proofs, which need an inference algorithm that respects proof terms:
% One-step inference algorithm
step : term -> prop -> type. % %mode step +A.
j0hyp : term -> prop -> type. % available non-hypothetical judgment
j1hyp : (term -> term) -> prop -> prop -> type.
% available hypothetical judgment
% immediate tactic
imm : j0hyp M A -> step M A.
% introduction tactics
bytrueI : step <> true.
by&I : j0hyp M A -> j0hyp N B -> step (M , N) (A & B).
by|IL : j0hyp M A -> step (inl M) (A | B).
by|IR : j0hyp M B -> step (inr M) (A | B).
by=>I : j1hyp M A B -> step (\ M) (A => B).
% elimination tactics
byfalseE : j0hyp M false -> step (abort M) A.
by&EL : j0hyp M (A & B) -> step (fst M) A.
by&ER : j0hyp M (A & B) -> step (snd M) B.
by|E : j0hyp M (A | B) -> j1hyp N A C
-> j1hyp L B C
-> step (case M N L) C.
by=>E : j0hyp M (A => C) -> j0hyp N A -> step (M N) C.
The checking of annotated proofs requires two judgments `avalid1' and `avalid2': The first returns a proof term and the second the proven proposition.
% Annotated proofs
aproof : type. %name aproof P.
afinal : term -> prop -> aproof. % P ::= M : A
aline : term -> prop -> aproof -> aproof. % | M : A; P
aframe : prop -> (term -> aproof) -> aproof -> aproof. % | [x: H; P]; P'
% Annotated proof checking
avalid1 : aproof -> term -> type. % %mode avalid1 +P -M.
avalid2 : aproof -> prop -> type. % %mode avalid2 +P -A.
avfinal1 : step M A -> avalid1 (afinal M A) M.
avfinal2 : step M A -> avalid2 (afinal M A) A.
avline1 : step M A -> (j0hyp M A -> avalid1 P N) ->
avalid1 (aline M A P) N.
avline2 : step M A -> (j0hyp M A -> avalid2 P B) ->
avalid2 (aline M A P) B.
avframe1 : ({x:term} j0hyp x H -> avalid1 (P x) (M x)) ->
({x:term} j0hyp x H -> avalid2 (P x) A) ->
(j1hyp M H A -> avalid1 Q N) -> avalid1 (aframe H P Q) N.
avframe2 : ({x:term} j0hyp x H -> avalid1 (P x) (M x)) ->
({x:term} j0hyp x H -> avalid2 (P x) A) ->
(j1hyp M H A -> avalid2 Q B) -> avalid2 (aframe H P Q) B.
Go to the first, previous, next, last section, table of contents.