(* Formalizing and Proving Theorems in Coq --- Homework 7 curated by Tobias Kappé, May 2022. This file demonstrates the use of records to encode a simple version of first-order logic using De Bruijn numbering. There are no homework exercises. *) From Equations Require Import Equations. (* First, let's define a relational signature as a type (of relation symbols) that comes equipped with an arity function. *) Record signature := { symbols: Type; arity: symbols -> nat; }. (* We are also going to need tuples of a certain type. This brings us to our first inductively defined dependent type. *) Inductive tuple (X: Type): nat -> Type := | TEmpty: tuple X 0 | TCons: X -> forall n, tuple X n -> tuple X (S n) . (* Let's have a look at the arguments of the constructors. *) Print tuple. (* Hmm, some of these arguments are not strictly necessary; we can make them implicit using the following vernacular. *) Arguments TEmpty {X}. Arguments TCons {X} _ {n}. (* Here is some boiler plate that makes Equations happy. *) Derive Signature for tuple. (* A model over a signature has a domain, and assigns to every symbol in that domain a relation of appropriate arity. This is where we use the tuple type that was defined above. *) Record model (sig: signature) := { domain: Type; relations: forall (sym: symbols sig), tuple domain (arity sig sym) -> Prop; }. (* Again we explicitly make some arguments implicit. *) Arguments domain {sig}. Arguments relations {sig}. (* Each instance of variable n represents one of n many variables. *) Inductive variable: nat -> Type := | VHere: forall n, variable (S n) | VThere: forall n, variable n -> variable (S n) . (* More boilerplate to keep Equations happy. *) Derive Signature for variable. (* More arguments that we need to make implicit. *) Arguments VHere {n}. Arguments VThere {n}. (* Here is our dependently typed syntax for formulas. The parameter n in formula sig n represents the number of free variables. *) Inductive formula (sig: signature): nat -> Type := | FTop: forall n, formula sig n (* Relational primitives consist of a symbol, and a tuple of variables from the current context of n-many variables, whose length matches the arity of the function symbol. *) | FRel: forall n (sym: symbols sig), tuple (variable n) (arity sig sym) -> formula sig n | FCon: forall n, formula sig n -> formula sig n -> formula sig n | FNeg: forall n, formula sig n -> formula sig n (* Universal quantification peels off one free variable. *) | FForall: forall n, formula sig (S n) -> formula sig n . (* More boilerplate for Equations and implicit parameters. *) Derive Signature for formula. Arguments FTop {sig} {n}. Arguments FRel {sig} {n}. Arguments FCon {sig} {n}. Arguments FNeg {sig} {n}. Arguments FForall {sig} {n}. (* This dependent type assigns a value to each variable in a context of n many variables. *) Inductive valuation {sig: signature} (mod: model sig): nat -> Type := | VEmpty: valuation mod 0 | VCons: domain mod -> forall n, valuation mod n -> valuation mod (S n) . Arguments VCons {sig} {mod} _ {n} _. (* The last bit of boilerplate that we need. *) Derive Signature for valuation. (* This is a helper function that looks up the value of a variable in a valuation. Note how var and val share the parameter n in their types, which means that the variable and valuation line up: there are n many possible choices of variable, each of which gets a value in the valuation. *) Equations lookup {sig: signature} {mod: model sig} {n: nat} (var: variable n) (val: valuation mod n) : domain mod := { lookup VHere (VCons x _) := x; lookup (VThere var) (VCons _ val) := lookup var val; }. (* Another helper function to map an m-tuple of variables over a context of size n into an m-tuple of values given a valuation. *) Equations lookup_all {sig: signature} {mod: model sig} {n m: nat} (vars: tuple (variable n) m) (val: valuation mod n) : tuple (domain mod) m := { lookup_all TEmpty _ := TEmpty; lookup_all (TCons var vars) val := TCons (lookup var val) (lookup_all vars val); }. (* Semantics for our first-order syntax, parameterized over a valuation for each of the free variables. Note that if there are no free variables, then the valuation VEmpty suffices. *) Equations interp {sig: signature} {mod: model sig} {n: nat} (val: valuation mod n) (fm: formula sig n) : Prop := { interp val (FTop) => True; interp val (FRel sym vars) => (* For relations, look up the n-ary relation in the model, and feed to it the interpretation of the n-ary tuple of variables. *) (relations mod sym) (lookup_all vars val); interp val (FCon fm1 fm2) => interp val fm1 /\ interp val fm2; interp val (FNeg fm) => ~ interp val fm; interp val (FForall fm) => (* For universal quantification, augment the valuation that we have with a universally quantified element of the domain to evaluate the inner formula, which needs a valuation for the additional symbol. *) forall (x: domain mod), interp (VCons x val) fm; }. (* Here's something we can prove now: universal quantification distributes over conjunction. *) Lemma forall_conjunction {sig: signature} {mod: model sig} {n: nat} (fm1 fm2: formula sig (S n)) (val: valuation mod n) : interp val (FForall (FCon fm1 fm2)) <-> interp val (FCon (FForall fm1) (FForall fm2)) . Proof. split; intros. - rewrite interp_equation_5 in H. rewrite interp_equation_3. repeat rewrite interp_equation_5. split; intros. + specialize (H x). rewrite interp_equation_3 in H. intuition. + specialize (H x). rewrite interp_equation_3 in H. intuition. - rewrite interp_equation_3 in H. destruct H. rewrite interp_equation_5. intros. rewrite interp_equation_3. split. + rewrite interp_equation_5 in H. apply H. + rewrite interp_equation_5 in H0. apply H0. Qed. (* As an encore, here is a way of defining the semantics using pure Coq functions and no functionality provided by the Equations plugin. As you can see, we need a generalized version of the "match" predicate, which returns a function that is fed the input valuation; this is necessary to convince the Coq type checker that the depenent types all line up. *) Fixpoint interp' {sig: signature} (mod: model sig) {n: nat} (val: valuation mod n) (fm: formula sig n) : Prop := match fm in formula _ m return valuation _ m -> Prop with | FTop => fun _ => True | FRel sym vars => fun val => relations mod sym (lookup_all vars val) | FCon fm1 fm2 => fun val => interp' mod val fm1 /\ interp' mod val fm2 | FNeg fm => fun val => interp' mod val fm | FForall fm => fun val => forall (x: domain mod), interp' mod (VCons x val) fm end val .