[Agda] proofs with "with"

Peter Selinger selinger at mathstat.dal.ca
Tue Dec 16 16:22:06 CET 2014


Sorry, I was obviously asleep when I responded to Wolfram's suggestion
last night. He had suggested eliminating "with" from the definition,
and I only eliminated "with" from the lemma instead.

When I am actually awake and do as Wolfram said, it does indeed work
correctly. First, I eliminate "with" from the lemma like this:

  newNat-aux : (L : List Nat) -> ∃[ n ∈ Nat ] (n ∉ L) -> Nat
  newNat-aux L [ n , p ] = n

  newNat : (L : List Nat) -> Nat
  newNat L = newNat-aux L (theorem-infinite L)

Then the proof works just fine, like this:

  lemma-newNat-aux : (L : List Nat) -> (x : ∃[ n ∈ Nat ] (n ∉ L)) -> newNat-aux L x ∉ L
  lemma-newNat-aux L [ n , p ] = p

  lemma-newNat : (L : List Nat) -> newNat L ∉ L
  lemma-newNat L = lemma-newNat-aux L (theorem-infinite L)

The point is that in this case, the auxiliary lemma states a more
general property of the auxiliary function; namely, it states that
(newNat-aux L x ∉ L), rather than the less general (newNat L ∉ L).
This can then be proved without using any "inspect"-like feature.

-- Peter

Peter Selinger wrote:
> 
> Wolfram Kahl wrote:
> > The "with" notation just generates an auxiliary function;
> > it is usually only a minor nuisance to generate that function
> > yourself.
> 
> Point well taken. Although writing the auxiliary function by hand does
> not entirely make the problem go away. In my example, if I write
> 
>   aux : (L : List Nat) -> ∃[ n ∈ Nat ] (n ∉ L) -> newNat L ∉ L
>   aux L [ n , p ] = ?
> 
>   lemma-newNat : (L : List Nat) -> newNat L ∉ L
>   lemma-newNat L = aux L (theorem-infinite L)
> 
> then in the context "?", I still end up with the hypothesis n ∉ L and
> the goal newNat L ∉ L, and no way to prove it. So I must pass the
> required equality as an additional argument to aux, like this:
> 
>   aux : (L : List Nat) -> (x : ∃[ n ∈ Nat ] (n ∉ L)) -> x == theorem-infinite L -> newNat L ∉ L
>   aux L [ n , p ] eq = ?
> 
>   lemma-newNat : (L : List Nat) -> newNat L ∉ L
>   lemma-newNat L = aux L (theorem-infinite L) refl
> 
> At this point, the solution is essentially equivalent to what
> "inspect" does, and arguably the auxiliary function has not increased
> transparency.
> 
> -- Peter
> 
> > On 15 December 2014 at 4:28:07 pm, Peter Selinger (selinger at mathstat.dal.ca) wrote:
> > 
> > This is a newbie question. I am being driven mad by proofs about  
> > definitions that use the "with" notation. The situation is typically  
> > like this:  
> > 
> > lemma : A -> B  
> > lemma x with expr  
> > lemma x | y = ?  
> > 
> > Within the proof context '?', a variable y is available, of the same  
> > type as expr. However, often, to complete the proof, one has to use  
> > the fact that y == expr. This fact is obviously true, but typically  
> > does not follow from anything in the proof context.  
> > 
> > The "rewrite" notation does not help here, because its purpose is to  
> > use an equation, not to prove one.  
> > 
> > Here is a concrete example (full definitions and proofs appended  
> > below). I have defined an operation for computing the maximum of a  
> > list of natural numbers:  
> > 
> > maximum : (L : List Nat) -> Nat  
> > 
> > I have also proved a lemma showing that the maximum is indeed an upper  
> > bound for the list:  
> > 
> > lemma-maximum : (L : List Nat) -> ∀ m -> m ∈ L -> m <= maximum L  
> > 
> > One can then easily prove a theorem stating that there are infinitely  
> > many natural numbers:  
> > 
> > theorem-infinite : (L : List Nat) -> ∃[ n ∈ Nat ] (n ∉ L)  
> > 
> > Since existential witnesses are not very convenient to use, I'd like  
> > to split this theorem into a first and second component: the first  
> > component is a function computing a natural number not in a given  
> > list, and the second component is the lemma saying that the number is  
> > indeed not in the list:  
> > 
> > -- Return a natural number not in L.  
> > newNat : (L : List Nat) -> Nat  
> > newNat L with theorem-infinite L  
> > newNat L | ([ n , p ]) = n  
> > 
> > -- The defining property of newNat.  
> > lemma-newNat : (L : List Nat) -> newNat L ∉ L  
> > lemma-newNat L with theorem-infinite L  
> > lemma-newNat L | ([ n , p ]) = ?  
> > 
> > However, I cannot complete the last proof. In principle, the question  
> > mark should just be "p". However, the prover (modulo beta reduction)  
> > serves  
> > 
> > Goal: newNat L ∉ L  
> > 
> > as the goal, and gives  
> > 
> > p : n ∉ L  
> > n : Nat  
> > L : List Nat  
> > 
> > as the hypotheses. Obviously, [ n , p ] was obtained by pattern  
> > matching theorem-infinite L, so we know that  
> > 
> > [ n , p ] == theorem-infinite L.  
> > 
> > >From this, we could immediately conclude that newNat L == n, which  
> > would immediately prove the goal. But I have not been able to find any  
> > combination of dot-patterns that the type checker would actually  
> > accept.  
> > 
> > Two questions:  
> > 
> > (1) what is the concrete solution to my problem?  
> > 
> > I realize that I can solve the problem by defining general first  
> > and second projections from the existential type:  
> > 
> > ∃fst : {A : Set} {B : A -> Set} -> ∃[ x ∈ A ] B x -> A  
> > ∃snd : {A : Set} {B : A -> Set} -> (p : ∃[ x ∈ A ] B x) -> B (∃fst p)  
> > 
> > and then I can just define newNat and lemma-newNat in terms of  
> > these. However, I am more concerned with what one can do when one  
> > is stuck in a proof context, rather than such an "external"  
> > solution to the problem.  
> > 
> > (2) why doesn't Agda do the obvious, namely, when matching a "with"  
> > expression "expr" against a pattern "p", just add the equation  
> > "expr == p" to the proof context? Is there an existing mechanism  
> > that can achieve this?  
> > 
> > Thanks, -- Peter  
> > 
> > Here's the full example. It requires no libraries.  
> > 
> > module InfNat where  
> > 
> > -- Falsity.  
> > data False : Set where  
> > -- no constructors.  
> > 
> > -- Negation.  
> > Not : Set -> Set  
> > Not A = A -> False  
> > 
> > -- Existential quantifier.  
> > data Exists (A : Set) (B : A -> Set) : Set where  
> > [_,_] : (a : A) -> B a -> Exists A B  
> > syntax Exists A (λ x -> B) = ∃[ x ∈ A ] B  
> > 
> > -- The natural numbers.  
> > data Nat : Set where  
> > zero : Nat  
> > succ : Nat -> Nat  
> > 
> > -- Order.  
> > data _<=_ : Nat -> Nat -> Set where  
> > z<=n : ∀ {n} → zero <= n  
> > s<=s : ∀ {m n} (m<=n : m <= n) → succ m <= succ n  
> > 
> > -- Order is reflexive.  
> > lemma-order-refl : ∀ {n} -> n <= n  
> > lemma-order-refl {zero} = z<=n  
> > lemma-order-refl {succ n} = s<=s lemma-order-refl  
> > 
> > -- Order is transitive.  
> > lemma-order-trans : ∀ {n m k} -> n <= m -> m <= k -> n <= k  
> > lemma-order-trans z<=n q = z<=n  
> > lemma-order-trans (s<=s p) (s<=s q) = s<=s (lemma-order-trans p q)  
> > 
> > -- Successor is not smaller.  
> > lemma-order-succ : ∀ {n} -> Not (succ n <= n)  
> > lemma-order-succ (s<=s h) = lemma-order-succ h  
> > 
> > -- The maximum of two numbers.  
> > max : Nat -> Nat -> Nat  
> > max zero m = m  
> > max n zero = n  
> > max (succ n) (succ m) = succ (max n m)  
> > 
> > -- Introduction rules for maximum.  
> > lemma-max-intro1 : ∀ n m -> n <= max n m  
> > lemma-max-intro1 zero m = z<=n  
> > lemma-max-intro1 (succ n) zero = lemma-order-refl  
> > lemma-max-intro1 (succ n) (succ m) = s<=s (lemma-max-intro1 n m)  
> > 
> > lemma-max-intro2 : ∀ n m -> m <= max n m  
> > lemma-max-intro2 zero m = lemma-order-refl  
> > lemma-max-intro2 (succ n) zero = z<=n  
> > lemma-max-intro2 (succ n) (succ m) = s<=s (lemma-max-intro2 n m)  
> > 
> > -- Lists.  
> > data List (A : Set) : Set where  
> > [] : List A  
> > _::_ : A -> List A -> List A  
> > 
> > -- Membership.  
> > data _∈_ {A : Set} (x : A) : (B : List A) -> Set where  
> > mem-head : {xs : List A} -> x ∈ (x :: xs)  
> > mem-tail : {xs : List A} {y : A} -> x ∈ xs -> x ∈ (y :: xs)  
> > 
> > -- Not member.  
> > _∉_ : {A : Set} -> (x : A) -> (B : List A) -> Set  
> > x ∉ B = Not (x ∈ B)  
> > 
> > -- Calculate the maximum of a list of numbers.  
> > maximum : (L : List Nat) -> Nat  
> > maximum [] = zero  
> > maximum (n :: L) = max n (maximum L)  
> > 
> > -- The maximum is an upper bound.  
> > lemma-maximum : (L : List Nat) -> ∀ m -> m ∈ L -> m <= maximum L  
> > lemma-maximum (n :: L) .n mem-head = lemma-max-intro1 n (maximum L)  
> > lemma-maximum (n :: L) m (mem-tail p) = lemma-order-trans (lemma-maximum L m p) (lemma-max-intro2 n (maximum L))  
> > 
> > -- Theorem: there are infinitely many natural numbers.  
> > theorem-infinite : (L : List Nat) -> ∃[ n ∈ Nat ] (n ∉ L)  
> > theorem-infinite L = [ n , p ]  
> > where  
> > n = succ (maximum L)  
> > p : n ∉ L  
> > p h = let q = lemma-maximum L n h in lemma-order-succ q  
> > 
> > -- Return a natural number not in L.  
> > newNat : (L : List Nat) -> Nat  
> > newNat L with theorem-infinite L  
> > newNat L | ([ n , p ]) = n  
> > 
> > -- The defining property of newNat.  
> > lemma-newNat : (L : List Nat) -> newNat L ∉ L  
> > lemma-newNat L with theorem-infinite L  
> > lemma-newNat L | ([ n , p ]) = {!!}  
> _______________________________________________
> Agda mailing list
> Agda at lists.chalmers.se
> https://lists.chalmers.se/mailman/listinfo/agda
> 



More information about the Agda mailing list