[Agda] Induction when the argument is wrapped in a constructor?

Nils Anders Danielsson nils.anders.danielsson at gmail.com
Wed Mar 26 17:41:07 CET 2008


On Fri, Mar 21, 2008 at 3:30 PM, Shin-Cheng Mu <scm at iis.sinica.edu.tw> wrote:

>    unfoldT↓ : {a : Set}(B : ℕ -> Set){n : ℕ} ->
>        (f : forall {i} -> B (suc i) -> ⊤ ⊎ a ⊎ (B i × B i)) ->
>          B n -> Tree a

>    data Split (a : Set): ℕ -> Set where
>      Sp : (xs : [ a ]) -> (bnd : ℕ) ->
>            length xs ≤ bnd -> Split a bnd

>    split↓ : forall {a i} ->
>      Split a (suc i) -> ⊤ ⊎ a ⊎ (Split a i × Split a i)
>
>  So far so good, except that it is now split↓ that fails
>  the termination check. The definition of split↓ is horrifying [...]

I think that the problem you have is, basically, that the structures
of the input and the decreasing measure do not match very well. One
alternative approach is to allow the indices to decrease arbitrarily
and use well-founded recursion:

  open import Logic.Induction.Nat

  data Split (P : Set -> ℕ -> Set) (a : Set) : ℕ -> Set where
    nul : Split P a 0
    tip : a -> Split P a 1
    bin : forall {n l r} -> l <′ 2 + n -> r <′ 2 + n ->
          P a l -> P a r -> Split P a (2 + n)

  unfold : forall {a} (P : Set -> ℕ -> Set) ->
           (forall {i} -> P a i -> Split P a i) ->
           forall {n} -> P a n -> Tree a
  unfold {a} P f {n} p = <-rec Pred helper n p
    where
    Pred = \n -> P a n -> Tree a

    helper : forall n -> <-Rec Pred n -> Pred n
    helper n             rec p with f p
    helper zero          rec p | nul               = Nul
    helper (suc zero)    rec p | tip x             = Tip x
    helper (suc (suc n)) rec p | bin le₁ le₂ p₁ p₂ =
      Bin (rec _ le₁ p₁) (rec _ le₂ p₂)

Then you can easily define split:

  split : forall {a n} -> Vec a n -> Split Vec a n
  split []           = nul
  split (x ∷ [])     = tip x
  split (y ∷ z ∷ xs) with split xs
  ... | nul               = bin ≤′-refl ≤′-refl           (y ∷ [])     (z ∷ [])
  ... | tip x             = bin ≤′-refl (≤′-step ≤′-refl) (y ∷ x ∷ []) (z ∷ [])
  ... | bin le₁ le₂ ys zs = bin le₁'    le₂'              (y ∷ ys)     (z ∷ zs)
    where
    le₁' = ≤′-step (s≤′s le₁)
    le₂' = ≤′-step (s≤′s le₂)

Note that this definition is rather inefficient, since the recursion
parameter "rec" above traverses the proofs. Perhaps one could hope
for the compiler to optimise away this inefficiency, though.

You could also have a look at "Why Dependent Types Matter", which
shows how you can do merge sort in a structurally recursive way. The
program developed in that paper does not use an unfold, though, so it
may not be very helpful to you.

I have attached a complete development, including fold and merge sort,
which works with Agda's current libraries.

-- 
/NAD
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MergeSort.agda
Type: application/octet-stream
Size: 2768 bytes
Desc: not available
Url : https://lists.chalmers.se/mailman/private/agda/attachments/20080326/b852044f/MergeSort.obj


More information about the Agda mailing list