[Agda] Re: Agda beats Coq

Nils Anders Danielsson nad at Cs.Nott.AC.UK
Fri Nov 21 11:01:56 CET 2008


On 2008-11-20 23:21, Dan Doel wrote:

> [...] all the unfolding that needs to happen to make types check
> automatically happens because of the observations we need to make.

This is the key point. I have another example, which I think illustrates
this well.

First an unsuccessful codata approach:

   -- Possibly infinite trees.

   codata Tree (A : Set) : Set where
     leaf : Tree A
     node : (l : Tree A) (x : A) (r : Tree A) -> Tree A

   map : forall {A B} -> (A -> B) -> Tree A -> Tree B
   map f leaf         ~ leaf
   map f (node l x r) ~ node (map f l) (f x) (map f r)

   -- Tree equality.

   codata _≈_ {A : Set} : (t₁ t₂ : Tree A) -> Set where
     leaf : leaf ≈ leaf
     node : forall {l₁ l₂ x₁ x₂ r₁ r₂}
            (l≈ : l₁ ≈ l₂) (x≡ : x₁ ≡ x₂) (r≈ : r₁ ≈ r₂) ->
            node l₁ x₁ r₁ ≈ node l₂ x₂ r₂

   map-cong : forall {A B} (f : A -> B) {t₁ t₂ : Tree A} ->
              t₁ ≈ t₂ -> map f t₁ ≈ map f t₂
   map-cong f leaf            ~ ?
   map-cong f (node l≈ x≡ r≈) ~ ?

How do you prove that map preserves equality? The type of the last goal
is

   map f (node .l₁ .x₁ .r₁) ≈ map f (node .l₂ .x₂ .r₂),

and the node constructor of _≈_ does not match this type. One can
perhaps get around this in some way, but the proof will likely be
inelegant.

Let's try to emulate Anton's approach instead (without his syntactic
sugar, since it has not been implemented):

   mutual

     data TreeD (A : Set) : Set where
       leaf : TreeD A
       node : (l : Tree A) (x : A) (r : Tree A) -> TreeD A

     codata Tree (A : Set) : Set where
       tree : (d : TreeD A) -> Tree A

   destruct : forall {A} -> Tree A -> TreeD A
   destruct (tree d) = d

   map : forall {A B} -> (A -> B) -> Tree A -> Tree B
   map f t with destruct t
   map f t | leaf       ~ tree leaf
   map f t | node l x r ~ tree (node (map f l) (f x) (map f r))

   mutual

     data _≈D_ {A : Set} : (t₁ t₂ : TreeD A) -> Set where
       leaf : leaf ≈D leaf
       node : forall {l₁ l₂ x₁ x₂ r₁ r₂}
              (l≈ : l₁ ≈ l₂) (x≡ : x₁ ≡ x₂) (r≈ : r₁ ≈ r₂) ->
              node l₁ x₁ r₁ ≈D node l₂ x₂ r₂

     -- Note that the type is not indexed on codata, only parameterised.

     codata _≈_ {A : Set} (t₁ t₂ : Tree A) : Set where
       tree : (d≈ : destruct t₁ ≈D destruct t₂) -> t₁ ≈ t₂

   destruct≈ : forall {A} {t₁ t₂ : Tree A} ->
               t₁ ≈ t₂ -> destruct t₁ ≈D destruct t₂
   destruct≈ (tree eq) = eq

   map-cong : forall {A B} (f : A -> B) {t₁ t₂ : Tree A} ->
              t₁ ≈ t₂ -> map f t₁ ≈ map f t₂
   map-cong f t₁≈t₂ with destruct≈ t₁≈t₂
   map-cong f {tree ._} {tree ._} t₁≈t₂ | leaf          ~ ?
   map-cong f {tree ._} {tree ._} t₁≈t₂ | node l≈ x≡ r≈ ~ ?

Now the last goal has type

   map f (tree (node .l₁ .x₁ .r₁)) ≈ map f (tree (node .l₂ .x₂ .r₂)).

Note that we can use the tree constructor of _≈_ here, because its type
matches anything. In

   map-cong f {tree ._} {tree ._} t₁≈t₂ | node l≈ x≡ r≈ ~ tree ?

the goal has type

   destruct (map f (tree (node .l₁ .x₁ .r₁))) ≈D
   destruct (map f (tree (node .l₂ .x₂ .r₂)))

which, due to the presence of destruct, evaluates to

   node (map f .l₁) (f .x₁) (map f .r₁) ≈D
   node (map f .l₂) (f .x₂) (map f .r₂),

which can easily be proved. Note that there is no need to use explicit
unfoldings; the use of destruct in the type of tree ensures that things
evaluate exactly when we want them to (in this example, at least).

(Note that the pattern matching on {tree ._} is not part of Anton's
approach, but I think it is harmless. In fact, both map and map-cong
could just as well be written without destruct(≈):

   map : forall {A B} -> (A -> B) -> Tree A -> Tree B
   map f (tree leaf)         ~ tree leaf
   map f (tree (node l x r)) ~ tree (node (map f l) (f x) (map f r))

   map-cong : forall {A B} (f : A -> B) {t₁ t₂ : Tree A} ->
              t₁ ≈ t₂ -> map f t₁ ≈ map f t₂
   map-cong f {tree ._} {tree ._} (tree leaf)            ~ tree leaf
   map-cong f {tree ._} {tree ._} (tree (node l≈ x≡ r≈)) ~
     tree (node (map-cong f l≈) (≡-cong f x≡) (map-cong f r≈))

However, destruct needs to be used in _≈_.)

-- 
/NAD



This message has been checked for viruses but the contents of an attachment
may still contain software viruses, which could damage your computer system:
you are advised to perform your own checks. Email communications with the
University of Nottingham may be monitored as permitted by UK legislation.



More information about the Agda mailing list