Zulip Chat Archive
Stream: lean4
Topic: Mutual inductive + abbrev
Yuri de Wit (Aug 10 2022 at 18:47):
I am trying to create a mutual declaration involving an abbrev and an inductive (through a structure, but that is an irrelevant detail).
However, it seems that I can't. Consider the following code snippet.
mutual -- ERROR: invalid mutual block
abbrev Env := Array Val
structure Closure where
e : Env
t : Tm
inductive Val : Type
| VVar (l : Lvl)
| VApp (l : Val) (a : Val) -- dont eval 'a' until needed
| VLam (x : Name) (c : Closure)
| VPi (x : Name) (A: Val) (c : closure) -- dont eval 'A' if not typechecking
| VU
deriving Inhabited
end
Is there a way around this?
Yuri de Wit (Aug 10 2022 at 18:52):
Based on the Declaration.lean, only mutual of inductives or mutual of definitions are supported, not even a mutual mixing definitions and inductives.
@[builtinCommandElab «mutual»]
def elabMutual : CommandElab := fun stx => do
let hints := { terminationBy? := stx[3].getOptional?, decreasingBy? := stx[4].getOptional? }
if isMutualInductive stx then
if let some bad := hints.terminationBy? then
throwErrorAt bad "invalid 'termination_by' in mutually inductive datatype declaration"
if let some bad := hints.decreasingBy? then
throwErrorAt bad "invalid 'decreasing_by' in mutually inductive datatype declaration"
elabMutualInductive stx[1].getArgs
else if isMutualDef stx then
for arg in stx[1].getArgs do
let argHints := getTerminationHints arg
if let some bad := argHints.terminationBy? then
throwErrorAt bad "invalid 'termination_by' in 'mutual' block, it must be used after the 'end' keyword"
if let some bad := argHints.decreasingBy? then
throwErrorAt bad "invalid 'decreasing_by' in 'mutual' block, it must be used after the 'end' keyword"
elabMutualDef stx[1].getArgs hints
else
throwError "invalid mutual block"
Yuri de Wit (Aug 10 2022 at 18:57):
Ok, I guess the workaround is obvious:
mutual
inductive Closure where
| mk (env : Array Val) (t: Tm)
inductive Val : Type
| VVar (l : Lvl)
| VApp (l : Val) (a : Val) -- call-by-need: dont eval 'a' until needed
| VLam (x : Name) (c : Closure)
| VPi (x : Name) (A: Val) (c : closure) -- dont eval 'A' if not typechecking
| VU
deriving Inhabited
end
David Thrane Christiansen (Aug 10 2022 at 20:46):
This is probably a conservative check to rule out induction-recursion, which vastly increases the power of the theory. I suspect that this would make elaborating recursive functions to eliminators much more tricky, and I don't know if I-R is compatible with all the other features of Lean, however.
Mario Carneiro (Aug 11 2022 at 05:34):
Another workaround is to use a notation to define Env
. You have to turn off quot.precheck
to make the notation go through though
Mario Carneiro (Aug 11 2022 at 05:36):
Here's an example from mathport: it starts with a local notation "Binders" => Array #Binder
, then uses that in the mutual induction, then ends with def Binders := Array #Binder
after the induction so you can use that as a real definition. The only downside is that the inductive constructors themselves have fields using Array #Binder
instead of the Binders
declaration.
Last updated: Dec 20 2023 at 11:08 UTC