# [Agda] Termination problems with "with" and recursion

Jan Stolarek jan.stolarek at p.lodz.pl
Mon Dec 2 14:09:46 CET 2013

```Ok, I think I need some more assistance :-)

Now let's say I have this definition:

data Heap : {i : Size} → Priority → Set where
empty : {i : Size} {n : Priority} → Heap {↑ i} n
node  : {i : Size} {n : Priority} → (p : Priority) → Rank → p ≥ n →
Heap {i} p → Heap {i} p → Heap {↑ i} n

≥ is evidence that p >= n. If I now extend merge with evidence like this:

merge : {i : Size} {p : Nat} → Heap {i} p → Heap {i} p → Heap p
merge empty h2 = h2
merge h1 empty = h1
merge .{↑ i} (node .{i} p1 l-rank p1≥p l1 r1) (node {i} p2 r-rank p2≥p l2 r2) with order p1 p2
merge .{↑ i} (node .{i} p1 l-rank p1≥p l1 r1) (node {i} p2 r-rank p2≥p l2 r2) | le p1≤p2
= makeT p1 p1≥p l1 (merge r1 (node p2 r-rank p1≤p2 l2 r2))
merge .{↑ i} (node .{i} p1 l-rank p1≥p l1 r1) (node {i} p2 r-rank p2≥p l2 r2) | ge p1≥p2
= makeT p2 p2≥p l2 (merge r2 (node p1 l-rank p1≥p2 l1 r1))

The termination checker complains on the second call to merge, but does not complain on the first
one. I am puzzled. Andreas, can you explain why the first case works and the second doesn't? They
seem to be symmetric. I'm attaching source file with definitions that I'm using.

Janek

Dnia poniedziałek, 2 grudnia 2013, Andreas Abel napisał:
> Here you go:
> Note that unconstraint sizes default to \inf, so you need to give sizes
> in type signatures where sizes are important, e.g. in merge.
>
> {-# OPTIONS --sized-types #-}
>
> open import Size
> open import Data.Bool
>
> module _ (Rank Priority : Set) (_<_ : Priority → Priority → Bool) where
>
> data Heap : {i : Size} → Set where
>    empty : {i : Size} → Heap {↑ i}
>    node  : {i : Size} → Priority → Rank → Heap {i} → Heap {i} → Heap {↑ i}
>
> module _ (makeT : Priority → Heap → Heap → Heap) where
>
>    merge : {i : Size} → Heap {i} → Heap {i} → Heap
>    merge empty h2 = h2
>    merge h1 empty = h1
>    merge (node p1 w1 l1 r1) (node p2 w2 l2 r2)  with p1 < p2
>    merge (node p1 w1 l1 r1) (node p2 w2 l2 r2)  | true  =
>      makeT p1 l1 (merge r1 (node p2 w2 l2 r2))
>    merge (node p1 w1 l1 r1) (node p2 w2 l2 r2)  | false =
>      makeT p2 l2 (merge (node p1 w1 l1 r1) r2)
>
> Depending on what makeT is, you might be able to give a more precise
> type to merge.
>
> On 02.12.2013 12:38, Jan Stolarek wrote:
> > Ok, I think I need some help with Sized types. I have a datatype
> > representing a Heap:
> >
> > data Heap : {i : Size} → Set where
> >    empty : {i : Size} → Heap {↑ i}
> >    node  : {i : Size} → Priority → Rank → Heap {i} → Heap {i} → Heap {↑
> > i}
> >
> > And I need to use sized types in merge function:
> >
> > merge : {i : Size} → Heap → Heap → Heap
> > merge h1 h2 with h1 | h2
> > merge h1 h2 | empty | _ = h2
> > merge h1 h2 | _ | empty = h1
> > merge h1 h2  | (node p1 w1 l1 r1)  | (node p2 w2 l2 r2)  with p1 < p2
> > merge h1 h2  | (node p1 w1 l1 r1)  | (node p2 w2 l2 r2)  | true  = makeT
> > p1 l1 (merge r1 h2) merge h1 h2  | (node p1 w1 l1 r1)  | (node p2 w2 l2
> > r2)  | false = makeT p2 l2 (merge h1 r2)
> >
> > Can I please have a hint how to do that? I tried adding annotation
> > according to this presentation:
> >
> > www2.tcs.ifi.lmu.de/~abel/talkAIM2008Sendai.pdf‎
> >
> > but with no success :-/ I keep getting errors like i != inf.
> >
> > Janek

-------------- next part --------------
{-# OPTIONS --sized-types #-}
module SizedMerge where

open import Size

data Bool : Set where
false : Bool
true  : Bool

data Nat : Set where
zero : Nat
suc  : Nat → Nat

Priority : Set
Priority = Nat

Rank : Set
Rank = Nat

data _≥_ : Nat → Nat → Set where
ge0 : {y : Nat}                   → y     ≥ zero
geS : {x : Nat} {y : Nat} → x ≥ y → suc x ≥ suc y

infixl 4 _≥_

_+_ : Nat → Nat → Nat
zero  + m = m
suc n + m = suc (n + m)

infixl 6 _+_

data Order : Nat → Nat → Set where
ge : {x : Nat} {y : Nat} → x ≥ y → Order x y
le : {x : Nat} {y : Nat} → y ≥ x → Order x y

order : (a : Nat) → (b : Nat) → Order a b
order a       zero    = ge ge0
order zero    (suc b) = le ge0
order (suc a) (suc b) with order a b
order (suc a) (suc b) | ge ageb = ge (geS ageb)
order (suc a) (suc b) | le bgea = le (geS bgea)

data Heap : {i : Size} → Priority → Set where
empty : {i : Size} {n : Priority} → Heap {↑ i} n
node  : {i : Size} {n : Priority} → (p : Priority) → Rank → p ≥ n →
Heap {i} p → Heap {i} p → Heap {↑ i} n

_≥ℕ_ : Nat → Nat → Bool
m     ≥ℕ zero  = true
zero  ≥ℕ suc n = false
suc m ≥ℕ suc n = m ≥ℕ n

rank : {n : Nat} → Heap n → Nat
rank empty            = zero
rank (node _ r _ _ _) = r

makeT : {n : Nat} → (p : Priority) → p ≥ n → Heap p → Heap p → Heap n
makeT p pgen l r with rank l ≥ℕ rank r
makeT p pgen l r | true  = node p (suc (rank l + rank r)) pgen l r
makeT p pgen l r | false = node p (suc (rank l + rank r)) pgen r l

merge : {i : Size} {p : Nat} → Heap {i} p → Heap {i} p → Heap p
merge empty h2 = h2
merge h1 empty = h1
merge .{↑ i} (node .{i} p1 l-rank p1≥p l1 r1) (node {i} p2 r-rank p2≥p l2 r2) with order p1 p2
merge .{↑ i} (node .{i} p1 l-rank p1≥p l1 r1) (node {i} p2 r-rank p2≥p l2 r2) | le p1≤p2
= makeT p1 p1≥p l1 (merge r1 (node p2 r-rank p1≤p2 l2 r2))
merge .{↑ i} (node .{i} p1 l-rank p1≥p l1 r1) (node {i} p2 r-rank p2≥p l2 r2) | ge p1≥p2
= makeT p2 p2≥p l2 (merge r2 (node p1 l-rank p1≥p2 l1 r1))
```