## Stream: new members

### Topic: Function decreasing on n-th argument

#### Pedro Minicz (Jul 03 2020 at 23:54):

How do I tell Lean that a given function is decreasing on the n-th argument? shift.main is "obviously" decreasing on the third argument (term (D + G)).

import tactic.linarith

inductive term : ℕ → Type
| app {G : ℕ} (M N : term G) : term G
| lam {G : ℕ} (M : term (G + 1)) : term G
| var {G : ℕ} (x : fin G) : term G

open term

def shift.elem : ∀ {G D : ℕ}, fin (G + D) → fin (G + D + 1)
| 0       D x          := x + 1
| (G + 1) D ⟨0, h⟩     := ⟨0, nat.lt.step h⟩
| (G + 1) D ⟨x + 1, h⟩ := shift.elem ⟨x, nat.lt_of_succ_lt h⟩

def shift.main : ∀ {G D : ℕ}, term (D + G) → term (D + G + 1)
| G D (app M N) := app (shift.main M) (shift.main N)
| G D (lam M)   := lam (shift.main M) -- Lean complains here.
| G D (var x)   := var (shift.elem x)


I suspect telling Lean that might not be enough, though, so for a second question: where can I read on well founded relations on Lean (and in general)?

#### Mario Carneiro (Jul 03 2020 at 23:56):

If this was a recursion on the third argument, it would not have D + G in the index

#### Mario Carneiro (Jul 03 2020 at 23:58):

Don't let well founded recursion errors fool you; that's just the fallback because the structural recursion compilation failed

#### Mario Carneiro (Jul 03 2020 at 23:58):

this should be a structural recursion

#### Pedro Minicz (Jul 04 2020 at 00:06):

Mario Carneiro said:

Don't let well founded recursion errors fool you; that's just the fallback because the structural recursion compilation failed

I see. That makes sense.

#### Pedro Minicz (Jul 04 2020 at 00:10):

Mario Carneiro said:

If this was a recursion on the third argument, it would not have D + G in the index

Yes! Indeed. Changing that fixed the issue.

#### Pedro Minicz (Jul 04 2020 at 01:25):

Why can't Lean see that M is structurally smaller than lam M. It may have something to do with the fact that lam M has type term Γ while M : term (Γ + 1).

import data.fin

@[derive decidable_eq]
inductive term : ℕ → Type
| app {Γ : ℕ} (M N : term Γ) : term Γ
| lam {Γ : ℕ} (M : term (Γ + 1)) : term Γ
| var {Γ : ℕ} (x : fin Γ) : term Γ

open term

def shift.main : ∀ {Γ : ℕ}, fin (Γ + 1) → term Γ → term (Γ + 1)
| Γ σ (app M N) := app (shift.main σ M) (shift.main σ N)
| Γ σ (lam M)   := lam (@shift.main (Γ + 1) (σ + 1) M)
| Γ σ (var x)   := var \$ if σ ≤ x then x + 1 else x

abbreviation shift {Γ : ℕ} : term Γ → term (Γ + 1) := shift.main 0

def subst.main : ∀ {Γ : ℕ}, fin (Γ + 1) → term Γ → term (Γ + 1) → term Γ
| Γ σ L (app M N) := app (subst.main σ L M) (subst.main σ L N)
| Γ σ L (lam M)   := lam (@subst.main (Γ + 1) (σ + 1) (shift L) M) -- This line.
| Γ σ L (var x)   := sorry


Last updated: Dec 20 2023 at 11:08 UTC