Zulip Chat Archive
Stream: metaprogramming / tactics
Topic: Determining whether a definition is recursive
Jannis Limperg (Oct 25 2023 at 12:53):
I'm trying to determine whether a name d
refers to a recursive definition. My first idea was to check whether d
occurs in its own value, but that doesn't work for well-founded and mutual recursion. E.g. the mutual
block
mutual
def f : Nat → Nat
| 0 => 0
| n + 1 => g n
def g : Nat → Nat
| 0 => 0
| n + 1 => f n
end
compiles to f x = f._mutual ... x ...
with f_mutual
an application of WellFounded.fix
and f
nowhere in sight.
I think I can work around this for my actual application, but I'd still be curious whether there's a nice way to figure this out.
Damiano Testa (Oct 25 2023 at 12:55):
Does docs#Lean.isRec help?
Mario Carneiro (Oct 25 2023 at 12:56):
no, that tells you if a definition is an inductive recursor
Mario Carneiro (Oct 25 2023 at 12:57):
you could either look at the equation lemmas, or you could look at the compiled IR to find the self reference
Mario Carneiro (Oct 25 2023 at 12:57):
Although, f._mutual
in the definition is also a clear indicator that the definition is recursive
Alex J. Best (Oct 25 2023 at 12:59):
You could also recursively search through definitions of constants occuring in the value (knowing that you can ignore declarations defined in some dependent module)
Mario Carneiro (Oct 25 2023 at 13:06):
@Alex J. Best that won't help, the kernel definition is in fact acyclic
Mario Carneiro (Oct 25 2023 at 13:06):
that's what the fix
reduction is about
Alex J. Best (Oct 25 2023 at 13:06):
Oh right!
Mario Carneiro (Oct 25 2023 at 13:09):
I think you can use docs#Lean.Compiler.mkUnsafeRecName to get the name of the compiler's partial def
corresponding to a recursive function, if it exists and/or is a mutualDefnDecl
then I think you found a recursive function
Mario Carneiro (Oct 25 2023 at 13:15):
import Lean
mutual
def f : Nat → Nat
| 0 => 0
| n + 1 => g n
def g : Nat → Nat
| 0 => 0
| n + 1 => f n
end
mutual
def f' : Nat → Nat
| 0 => 0
| n + 1 => g' n
def g' : Nat → Nat
| 0 => 0
| n + 1 => g' n
end
open Lean
def isRecursive (env : Environment) (n : Name) : Bool := Id.run do
env.contains (Lean.Compiler.mkUnsafeRecName n)
#eval show Elab.Command.CommandElabM _ from do
println! isRecursive (← getEnv) ``f -- true
println! isRecursive (← getEnv) ``g -- true
println! isRecursive (← getEnv) ``Nat.add -- true
println! isRecursive (← getEnv) ``Nat.succ -- false
println! isRecursive (← getEnv) ``Nat -- false
println! isRecursive (← getEnv) ``f' -- false
println! isRecursive (← getEnv) ``g' -- true
Last updated: Dec 20 2023 at 11:08 UTC