(* 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
.