I'm having some trouble convincing Agda that an argument in a recursive call to a function is structurally smaller than the incoming argument.
I have defined pairs, lists of pairs (representing finite functions as "sets" of input/output pairs), and unions of such lists as follows:
data _x_ {l : Level} (A B : Set l) : Set l where
<_,_> : A -> B → A x B
data FinFun (A B : Set) : Set where
nil : FinFun A B
_::_ : A x B → FinFun A B → FinFun A B
_U_ : {A B : Set} -> FinFun A B -> FinFun A B -> FinFun A B
nil U f' = f'
(x :: xs) U f' = x :: (xs U f')
I have also defined "neighborhoods" and the supremum of two such neighborhoods:
data UniNbh : Set where
bot : UniNbh
lam : FinFun UniNbh UniNbh -> UniNbh
_u_ : UniNbh -> UniNbh -> UniNbh
bot u bot = bot
bot u (lam f) = lam f
(lam f) u bot = lam f
(lam f) u (lam f') = lam (f U f')
Finally, and most importantly for this question, I have defined a function which, given a list of pairs of neighborhoods, takes the supremum of all the first components of the pairs in the list:
pre : FinFun UniNbh UniNbh -> UniNbh
pre nil = bot
pre (< x , y > :: f) = x u pre f
The mutually recursive function that causes me trouble essentially looks like this:
f : UniNbh -> UniNbh -> UniNbh -> Result
-- Base cases here. When any argument is bot or lam nil, no
-- recursion is needed.
f (lam (a ∷ as)) (lam (b ∷ bs)) (lam (c ∷ cs)) =
f (lam (a ∷ as)) (pre (b ∷ bs)) (lam (c ∷ cs))
It seems obvious that either pre f is smaller than lam f, or that one of the base cases will end the recursion, but Agda understandably can't see this. I have tried quite a few different ideas in trying to solve this, but they haven't worked. At this point, I think that the only way is to use Induction.WellFounded from the standard library, but I can't figure out how.
I've unsuccessfully tried to show that the following data type is well founded:
data preSmaller : UniNbh -> UniNbh -> Set where
pre-base : preSmaller (pre nil) (lam nil)
pre-step : ∀ (x y f f') ->
preSmaller (pre f) (lam f') ->
preSmaller (pre (< x , y > :: f')) (lam (< x , y > :: f'))
I'm not even sure that this data type would be useful, even if I could prove that it's well founded.
When looking around trying to find information about how to use Induction.WellFounded, I can only find very simple examples showing that < for natural numbers is well founded, and I haven't been able to generalize those ideas to this situtation.
Sorry for the long post. Any help would be greatly appreciated!