Zulip Chat Archive

Stream: general

Topic: nested recursion


Kana (Feb 17 2021 at 20:25):

is it possible to write such function?

inductive rec
| mk : list (string × rec)  rec

-- unexpected occurrence of recursive function
def rec.map (f : rec  rec) : rec  rec
| (rec.mk xs) := rec.mk (prod.map id rec.map <$> xs)

Mario Carneiro (Feb 17 2021 at 20:26):

nested inductives are not really supported in lean, they are compiled (badly) to inductive types. It's better to roll your own inductive type if you want the right recursion principle

Mario Carneiro (Feb 17 2021 at 20:27):

although you can also sort of ignore the foundational issues if you use meta inductive

Mario Carneiro (Feb 17 2021 at 20:28):

which is probably fine if this is intended for code execution

Kana (Feb 17 2021 at 20:28):

I want just to write has_repr instance for such type

Kana (Feb 17 2021 at 20:28):

Maybe there is some way to derive that instance?

Mario Carneiro (Feb 17 2021 at 20:28):

I think it's best to imagine that the inductive line itself failed

Mario Carneiro (Feb 17 2021 at 20:30):

you can't define any functions by structural recursion on this type without a lot of manual work

Mario Carneiro (Feb 17 2021 at 20:30):

So my question for you is whether you want a type you can run functions on in the VM, or a type you can prove things about by induction/recursion

Mario Carneiro (Feb 17 2021 at 20:31):

If it is the former, the solution is easy:

inductive rec
| mk : list (string × rec)  rec

meta def rec.map (f : rec  rec) : rec  rec
| (rec.mk xs) := rec.mk (prod.map id rec.map <$> xs)

Mario Carneiro (Feb 17 2021 at 20:31):

or, probably better,

meta inductive rec
| mk : list (string × rec)  rec

meta def rec.map (f : rec  rec) : rec  rec
| (rec.mk xs) := rec.mk (prod.map id rec.map <$> xs)

Kana (Feb 17 2021 at 20:31):

Okay. I have such type

inductive value
  | string : string  value
  | object : list (string × value)  value
  | array : list value  value
  | number :   value
  | bool : bool  value
  | null : value

and all what I want is just to print value of this type via #eval, so I want has_repr or has_to_string instance, but I can't write it

Kana (Feb 17 2021 at 20:32):

thanks, I will try meta

Mario Carneiro (Feb 17 2021 at 20:34):

If you want to prove things about it, you should unfold the nested inductive into a plain inductive:

inductive rec
| nil : rec
| cons : string  rec  rec  rec

def rec.map (f : rec  rec) : rec  rec
| rec.nil := rec.nil
| (rec.cons s x xs) := rec.cons s x.map xs.map

Mario Carneiro (Feb 17 2021 at 20:38):

A cheating way to fix your json type is to unfold the object and array constructors into nil/cons

inductive value
| string : string  value
| object_nil : value
| object_cons : string  value  value  value
| array_nil : value
| array_cons : value  value  value
| number :   value
| bool : bool  value
| null : value

The problem with this is that there are some values of this type that are not valid json, for instance array_cons v object_nil. For most code this doesn't matter since it's being validated into a more precise type anyway, but it's possible to encode this invariant as a predicate or as an index in the type

Mario Carneiro (Feb 17 2021 at 20:39):

But from your description I think meta is the way to go, termination checking doesn't matter for your use case

Kana (Feb 17 2021 at 20:41):

Thanks! meta works great for me


Last updated: Dec 20 2023 at 11:08 UTC