# 15-317 Constructive Logic Recitation 10: Intrinsic Encodings

Today in recitation, we went over two Homework 6 problem solutions, one an invertibility (∀R) and one a non-invertibility (∀L). The full story can be found in the sample solution, but the take-home point is the following: when asked to prove "If J1, then J2", you must work parametrically from an unknown proof of J1, taking all instances into account; but when asked to refute such a statement, it suffices merely to provide a counterexample, i.e. to choose an instance of J1 which you know to be derivable and argue that the corresponding instance of J2 is not.

Then, we learned the story of intrinsic encodings. By systematically transforming and reintepreting the code from lecture for representing props and proofs, we can obtain a representation of intrinsically well-formed proofs which obviates the need for a proof-checking judgement.

Reviewing the code from lecture, we saw that the judgements-as-types methodology represents on-paper judgements using type families in the logical framework. So the on-paper proof-checking judgement M : A becomes a type family

`    \$ : proof -> prop -> type.  `
Now the type `M \$ A` represents the judgement M : A, and elements `D` of the type `M \$ A` represent derivations of the judgement M : A. Thus, inference rules for deriving M : A become constructors for building elements of the type `M \$ A`. For instance the rule ∧I becomes:
```    /\I : pair M N  \$  A /\ B
<- M \$ A
<- N \$ B.```

Early in the semester we had a natural deduction judgement A true and various rules for constructing derivations of this judgement. The rules were in one-to-one correspondence with the rules used for deriving the judgement M : A, but without proof terms. We can easily represent this in the logical framework LF by inventing a new type family to represent the judgement:

`    true : prop -> type.`
and by populating it by constructors corresponding to the rules. We can follow our intuition regarding the correspondence between M : A and A true: the rules populating `true A` are exactly the rules populating `M \$ A` with the proof terms erased and the type family changed. For instance:
```    /\I : true (A /\ B)
<- true A
<- true B. ```

We can take this one step further, in fact, by realizing that proof terms are also in one-to-one correspondence with derivations. Then instead of reading the type `true A` as the judgement that a proposition `A` is provable, we can read it as the type family of well-formed proof terms. If we rename the rules using the proof term constructors and write the arrows in the usual forward direction, we get:

`    pair : true A -> true B -> true (A /\ B).`
To complete the interpretation, we can rename `true` to `proof` and dispense with our earlier non-intrinsic proof type.
```    proof : prop -> type.

pair : proof A -> proof B -> proof (A /\ B).```
Now we have an intrinsic encoding of well-formed proofs: we cannot even write down an ill-formed proof or it will not typecheck as an LF term. In essence this is what you get if you interpret natural deduction derivations as programs directly rather than taking the detour of introducing proof terms and annotating the rules appropriately.

It is worth examining the steps of the above transformation in detail, so I encourage you to look at and compare the three Twelf files listed below in the references. We go from raw proof terms with a formation judgement `M \$ A` to bare natural deductions `true A`, and then we reinterpret those deductions as intrinsically well-formed proof terms. This is a highly general and elegant technique that is often used when encoding logics in the logical framework: we leverage typechecking in LF to rule out ill-formed proofs in our logic.

References:

fp@cs
Frank Pfenning