[Agda] Agda goes coinductive

Dan Doel dan.doel at gmail.com
Sat Jun 7 14:29:26 CEST 2008


On Saturday 07 June 2008, Nils Anders Danielsson wrote:
> This is not strictly necessary. If you define your predicates in terms
> of destructors (basically Anton's case) instead of indexing on
> constructor applications then you can avoid this use of unfolding
> functions:

Well, this is the sort of thing I was looking for, I suppose. I was able to 
rewrite things in this way so that I can complete proofs *and* keep the 
termination/productivity checker happy. For instance, here's the mapD 
convergence proof:

---- snip ----

data Converge {a : Set} : D a -> a -> Set where
  converge-now   : {x : D a} (v : a) -> 
                   (eq : destruct x == now v) ->
                   Converge x v
  converge-later : {x : D a}{x' : D a} {v : a} ->
                   (eq : destruct x == later x') ->
                   Converge x' v -> Converge x v

mapD' : {a b : Set} -> (a -> b) -> D' a -> D' b
mapD' f (now v)    = now (f v) 
mapD' f (later dv) = later (mapD f dv)

map-now : {a b : Set}
          {v : a}
          (x : D a)
          (f : a -> b) ->
          destruct x == now v ->
          destruct (mapD f x) == now (f v)
map-now {a} {b} {v} (now .v) f refl = refl 
map-now (later dv) f ()

map-later : {a b : Set}
            (v : a)
            (x  : D a)
            {dx : D a}
            (f : a -> b) ->
            destruct x == later dx ->
            destruct (mapD f x) == later (mapD f dx)
map-later v (now v')    f ()
map-later v (later dx) f refl = refl 

map-converge : {a b : Set}{x : D a}{v : a}{f : a -> b} ->
               Converge x v -> Converge (mapD f x) (f v)
map-converge {a} {b} {x} {v} {f} (converge-now .v eq) = converge-now (f v) 
(map-now x f eq )
map-converge {a} {b} {x} {v} {f} (converge-later eq pfc)
             = converge-later (map-later v x f eq) (map-converge pfc)

---- snip ----

The never divergence proof failed the productivity checker in my scheme, but 
works fine in this one:

---- snip ----

diverge-never : {a : Set} -> Diverge (never {a})
diverge-never ~ diverge never refl diverge-never

---- snip ----

And this theorem failed the termination checker, but works under this scheme:

---- snip ----

race : {a : Set} (x y : D a) -> D a
race (now v)    y           ~ now v
race (later dv) (now v)     ~ now v
race (later dv) (later dv') ~ later (race dv dv')

data _||_ (P Q : Set) : Set where
  pfl : P -> P || Q
  pfr : Q -> P || Q

race-converge : {a : Set} {x y : D a} {v : a} ->
                Converge (race x y) v -> Converge x v || Converge y v
race-converge {a} {now .v} {y} {v} (converge-now .v refl)
  = pfl (converge-now v refl) 
race-converge {a} {later dv} {now .v} {v} (converge-now .v refl)
  = pfr (converge-now v refl)
race-converge {a} {later dv} {later dv'} {v} (converge-now .v ())
race-converge {a} {now v} (converge-later () pfc)
race-converge {a} {later dv} {now v} (converge-later () pfc)
race-converge {a} {later dv} {later dv'} (converge-later refl pfc) with 
race-converge pfc
...           | pfl pfx = pfl (converge-later refl pfx)
...           | pfr pfy = pfr (converge-later refl pfy)

> However, I am not really fond of this programming style. The defining
> feature of Agda is dependent pattern matching over inductive families,
> and using destructors and explicit equalities feels like a step
> backwards. I hope that we can find an elegant system which allows
> dependent pattern matching over coinductive families.

Yeah, I think I agree. As a visible side effect, there's an explosion of cases 
in proofs with the equalities. That race-convergence proof has 3 cases (+ 2 
with cases) in my original, but there are 6 (+2) in the above, because of the 
required matches with the absurd pattern. The equality shuffling in 
map-converge isn't a lot of fun either (maybe I could rewrite it to be all 
one function, but I suspect there'd be a similar introduction of lots of 
absurd patterns).

In the inductive case, Agda manages to get a lot done without both tedium and 
extensive automation. Hopefully the same will be true in the coinductive case 
(as an aside, when I started getting frustrated translating the proofs in the 
paper into Agda, I went and looked at the Coq code referenced in the paper; 
it was pretty much no help to me. Perhaps that's just because I don't know 
Coq, but it also seemed that most of the proofs were lists of stuff for the 
proof assistant to do automatically, which seems to me less illuminating as 
to what's actually happening in the proof than when I write such things in 
Agda).

Cheers.

-- Dan Doel


More information about the Agda mailing list