[Agda] Proof irrelevance and self-realizing formulas

Andreas Abel andreas.abel at ifi.lmu.de
Sat May 30 19:53:19 CEST 2009


Hi Conor,

On May 30, 2009, at 1:32 PM, Conor McBride wrote:
> If you want to identify proofs judgmentally, there's
> only one way to get it: laziness. Any strict evaluation
> rules which demand a canonical proof to trigger
> computation effectively discriminate between canonical
> and non-canonical proofs. Note that absurdity elimination
> has no such strict rules! If you want
>
> subst : (x y : X) -> x == y ->
>         (P : X -> Set) -> P x -> P y
>
> you had better not rely on
>
> subst _ _ refl _ p = p
>
> for its evaluation behaviour (although you'd hope it
> would still be true). This toxic mixture of proof
> irrelevance and strictness is what was a wee bit broken
> with Agda's experimental Prop (see archives). The same
> bug can be found in Epigram 1 (must add it to the
> collection of horror stories
> http://strictlypositive.org/Ripley.pdf I started last
> week). Once you can ensure that the form of a proof
> has no influence on the course of open computation,
> then you can identify proofs judgmentally: proof
> irrelevance cannot just be decreed; it must be achieved.

You make me curious.  I have read the Ripley cabinet and find myself  
already mentioned in an unglorious way [you are right, the non- 
transitive codata equality is implemented in MiniAgda].  I wish not to  
contribute again [why not? mistakes increase knowledge], so maybe you  
have a comment on the following proposal on how I want to achieve  
proof irrelevance for _==_ before I edge it into stone:

We consider proof-irrelevant equality with

   Gamma |- p, q : Id S s s'
   ---------------------------------- (eta)
   Gamma |- p = q : Id S s s'

and the abovementioned beta-rule for subst.  Now I am implementing NbE- 
style type-directed normalization. Here is the idea (boring equations  
omitted):

   nf {(x:S) -> T}  t = \x -> nf {[s/x]T} (t at s)    where s = up {S}  
x   (assume x fresh for t)
   nf {Id S s s'}    t = whnf t                             [results  
in * or refl if everything is welltyped]

   up {Id S s s'}   u = refl                               if  nf {S}  
s = nf {S} s
                               = *                                    
otherwise
   up {(x:S) -> T} u = Up {(x:S) -> T} u

   whnf (r s)                          = (whnf r) @ s
   whnf (subst _ _ refl _ p) = whnf p

   (\xt)@ s                    = whnf ([s/x]t)
   Up{(x:S) -> T} @ s = up {[s/x]t} (u (nf {S} s))

nf is supposed to compute a unique eta-long normal form. At function  
type it introduces a fresh variable which is immediately "reflected"  
via up.  up takes a neutral normal form u and eta-expands it.  At  
identity type Id S s s' it checks whether s and s' have the same  
normal form; in this case u is expanded to refl, otherwise to *.  The  
main idea, coming from NbE, is that up at function type delays the eta- 
expansion. Only when it is applied (last equation), eta-expansion  
continues.

nf can be used on open terms if all free variables x:S are replaced by  
(up {S} x) first.

So, indeed I am distinguishing between canonical and non-canonical  
proofs.  To be more precise, I am distinguishing between p : Id T t t  
and q : Id T t t' where t, t' have different normal forms. I am aware  
that this makes nf non-compositional, in particular, to compute nf(r  
s), the normal form of r is unusable.  For example:

   T = (x,y:S) -> Id S x y -> Id S x y
    t : T
    t x y p = p

   nf {T} t = \x\y\p.*

   nf {...} (t x x) = \p.refl

But since I only compute nf's to check for type equality, and throw  
them away afterwards, I think I am safe.

Indeed, there is some lazyness in my approach, but not in subst, but  
in eta-expansion (reflection/unquote).

Cheers,
Andreas





More information about the Agda mailing list