Limit the possible constructor in another type constuctor

Maybe I don’t understand GADT correctly, but I want to limit which constructors are available in a certain type

lvalue can be a bunch of things, but for HashSet statement, I want to limit lvalue to be Variable of string, not the other constructors.

and lvalue =
    | Variable of identifier
    | Property_access of class_property_name
    | Object_access of identifier * lvalue

and statement = 
   | Hash_set of {
       hash_var: lvalue;  (* Limit this to Variable only? *)
       hash_typ: typ; 
       key: expression;  
       value: expression;
   }

(hash_typ will be limited to certain values, too, unless the ast becomes too complicated.)

One solution from Kali:

type variable = | (* empty type, since the actual type is being used as a tag, it doesn't need any constructors, although you could just give it one constructor like Variable if you wanted *)
type not_variable = |

...
and _ lvalue = 
  | Variable : identifier -> variable lvalue
  | Property_access : class_property_name -> not_variable lvalue
  | Object_access : identifier * _ lvalue -> not_variable lvalue
and statement =
  | Hash_set of {
    hash_var : variable lvalue;
...

just note that the issue with this method is that because the types of those constructors are distinct, you have to do something to erase the type variable if you ever want to put a Variable … and a Property_access … in the same container / return them from the same function

you can’t i.e. have a variable lvalue list containing Property_access or Object_access or vice versa

type erased_lvalue = Erase : _ lvalue -> erased_lvalue

In this case, you can unbox the identifier:

   | Hash_set of {
       hash_var: identifier; 
       hash_typ: typ; 
       key: expression;  
       value: expression;
   }

Also using empty types as type-level tag doesn’t work for your purpose. You want to keep your tags distinguishable:

type variable = private Tag_variable (* tag-level type*)
type not_variable = private Tag_not_variable

Otherwise, the typechecker cannot prove that variablenot_variable outside of the module that defined the two tags.

1 Like

Hmmm yea maybe, tho I’d have to apply a fix in the parser for this case then. But that makes sense.