Zulip Chat Archive

Stream: general

Topic: nested data types


Hans-Dieter Hiep (Feb 14 2019 at 10:41):

Hi! I am trying to define a nested data type, but encounter some confusing error messages. I have reduced the problem to the following small case:

inductive tree (α : Type) (current : {x : α // true})
| ite: α → list tree → list tree → tree

It gives the error: nested occurrence 'list.{0} (tree α current)' contains variables that are not parameters.
Removing the parameter current gets rid of the error.
Can someone explain what is going on?
How can I still make use of such a parameter?

Mario Carneiro (Feb 14 2019 at 10:42):

what is it doing there? You aren't using it

Hans-Dieter Hiep (Feb 14 2019 at 10:42):

True, but in the definition with the same error, I do use it.

Hans-Dieter Hiep (Feb 14 2019 at 10:42):

inductive stmt (α : Type) (H : signature α)
    (self : class_name α) (e : tenv self) : Type 1
| ite: pexp e (boolean α)  list stmt  list stmt  stmt
| while: pexp e (boolean α)  list stmt  stmt
| assign {ty : type α} (l : svar e ty):
    pexp e ty  stmt
| async {c : class_name α} {m : method_name c}
    {H : m  constructor c}
    (o : rvar e (ref c))
    (τ : arglist e m): stmt
| alloc {c : class_name α}
    (l : svar e (ref c))
    (τ : arglist e (constructor c)): stmt

Mario Carneiro (Feb 14 2019 at 10:43):

Also this is a nested inductive, those aren't handled well

Mario Carneiro (Feb 14 2019 at 10:43):

If you can avoid list stmt it will be better

Mario Carneiro (Feb 14 2019 at 10:43):

for example adding a seq constructor

Mario Carneiro (Feb 14 2019 at 10:43):

and nop I guess

Hans-Dieter Hiep (Feb 14 2019 at 10:44):

Yes, that was my previous approach. However, I was trying to find out whether working with nested lists of stmt would work too.

Mario Carneiro (Feb 14 2019 at 10:45):

Why the type 1?

Hans-Dieter Hiep (Feb 14 2019 at 10:45):

That's because ty : type \alpha consists of all inhabited Types with decidable equality.

Mario Carneiro (Feb 14 2019 at 10:47):

I think this is just an issue with nested inductive compilation. It's pretty buggy, we're working on a replacement

Mario Carneiro (Feb 14 2019 at 10:47):

You can also do the nested inductives yourself if you really want it like this

Hans-Dieter Hiep (Feb 14 2019 at 10:48):

OK, that seems reasonable. Thanks, @Mario Carneiro !

Mario Carneiro (Feb 14 2019 at 10:48):

This is what it looks like as a plain inductive:

inductive stmt (α : Type) (H : signature α)
    (self : class_name α) (e : tenv self) : bool  Type 1
| ite: pexp e (boolean α)  stmt tt  stmt tt  (stmt ff)
| while: pexp e (boolean α)  stmt tt  (stmt ff)
| assign {ty : type α} (l : svar e ty):
    pexp e ty  (stmt ff)
| async {c : class_name α} {m : method_name c}
    {H : m  constructor c}
    (o : rvar e (ref c))
    (τ : arglist e m): (stmt ff)
| alloc {c : class_name α}
    (l : svar e (ref c))
    (τ : arglist e (constructor c)): (stmt ff)
| nil : stmt tt
| cons : stmt ff  stmt tt  stmt tt

Mario Carneiro (Feb 14 2019 at 10:49):

the actual stmt is stmt ff here, and stmt tt is isomorphic to list (stmt ff)

Hans-Dieter Hiep (Feb 14 2019 at 10:52):

Wow, that seems to be what I was looking for! So, if I understand correctly, the bool argument determines what constructors are applicable.

Mario Carneiro (Feb 14 2019 at 11:04):

right. This is actually what the nested inductive type you wrote (is supposed to) compile to

Edward Ayers (Feb 14 2019 at 11:07):

Mutual inductives also compile down to something like this right?

Mario Carneiro (Feb 14 2019 at 11:08):

yes, technically it's two-step, the nested inductive translates to a mutual inductive of stmt and list_stmt, and that gets compiled to an indexed inductive like the above

Edward Ayers (Feb 14 2019 at 11:09):

So if I may highjack the converstation; am I right in remembering there were talks to put mutual inductives in the kernel? Why bother if you can get them to compile down?

Mario Carneiro (Feb 14 2019 at 11:09):

because they are slow

Mario Carneiro (Feb 14 2019 at 11:10):

the kernel "sees" the entire compilation process when trying to reduce the computation rule

Mario Carneiro (Feb 14 2019 at 11:11):

Also they are slow to compile the initial definitions; if you watch how long it takes to compile a nested inductive vs a plain inductive it's way slower

Mario Carneiro (Feb 14 2019 at 11:12):

And mutual defs have to be done by well founded recursion, which is hit or miss

Hans-Dieter Hiep (Feb 19 2019 at 12:23):

You can also do the nested inductives yourself if you really want it like this

Similarly, I can solve the mutual inductive definition by doing it myself:

inductive pexp (e : tenv self) : list (type α)  Type 1
| const (c : constant_name α): pexp [result_type c]
| app (f : function_name α):
    pexp (args_type f)  pexp [result_type f]
| lookup {ty : type α}: rvar e ty  pexp [ty]
| requal {c : class_name α}:
    pexp [type.ref c]  pexp [type.ref c]  pexp [boolean α]
| nil: pexp []
| cons {ty : type α} {l : list (type α)}:
    pexp [ty]  pexp l  pexp (ty::l)

Is accepted without error.


Last updated: Dec 20 2023 at 11:08 UTC