Zulip Chat Archive

Stream: new members

Topic: recursion in list


Catarina Gamboa (Feb 28 2022 at 17:40):

Hello, I am new to lean, and I am having difficulties in invoking a recursive function. I am trying to define a subtitution function with the following inductive type and definition:

inductive exp
| var     : string  exp
| app     : string  list exp  exp

def substitute: string  exp  exp  exp -- (substitute arg₀ by arg₁ in arg₂)
| v e (exp.var s)    := if v = s then e else (exp.var s)
| v e (exp.app s le) := exp.app s (le.map (λ x, substitute v e x))

However, the subtitution inside the map provokes the error message "failed to prove recursive application is decreasing, well founded relation". Do you have any suggestions to overcome this issue?

Jannis Limperg (Feb 28 2022 at 17:50):

Your exp is a nested inductive type because exp appears recursively as an argument to a different type (list). As you've discovered, such types are poorly supported by Lean's termination checker. There are two ways forward:

  • Use well-founded induction. This is a technique that allows you to prove a function terminates even when Lean doesn't immediately see it. There should be a section in the mathlib docs about this.
  • Restructure your type to avoid the nesting. If possible, this would be my preferred choice.

Coq supports nested inductives better btw, though afair the experience is not super great there either.

Martin Dvořák (Feb 28 2022 at 17:57):

Jannis Limperg said:

There should be a section in the mathlib docs about this.

Did you mean?
https://leanprover-community.github.io/extras/well_founded_recursion.html

Floris van Doorn (Feb 28 2022 at 19:20):

You'll have a much nicer time if you make the type app : ∀ {n}, string → (fin n → exp) → exp (which is one particular way to do choice (2) suggested by Jannis).


Last updated: Dec 20 2023 at 11:08 UTC