Right, I have this data type in Rascal:
data Type = Any() | Void() | Int() | Not(Type l) | And(set[Type] es) | Or(set[Type] es);
What I want to do is define another type like this:
data Primitive = Any() | Void() | Int();
And then be able to do things like this:
Primitive p = Any();
Type d = p;
Or, for example, match against Primitive
when simplifying Type
. Something like this:
public Type reduce(Not(Primitive p)) = p;
Currently, the only solution I can see is to expand the above rule for each case like so:
public Type reduce(Not(Any)) = Any();
public Type reduce(Not(Void)) = Void();
public Type reduce(Not(Int)) = Int();
I'm guessing there is a way to do this, but I didn't figure it out yet ... thoughts?
The short answer: although Abstract Data Types can be extended (i.e., their definition can be extended across modules) there is no direct inheritance.
Work arounds:
Solution A
data Type = Any() | Void() | Int() | Not(Type l) | And(set[Type] es) | Or(set[Type] es);
bool isPrim(Any()) = true;
bool isPrim(Void()) = true;
bool isPrim(Int()) = true;
default bool isPrim(Type t) = false;
Type reduce(Not(Type t)) = t when isPrim(t);
default Type reduce(Type t ) = t;
Here all constructors for Type
are in a single ADT and the predicate isPrim
selects the primitives. For example, reduce(Not(Void()))
will reduce to Void()
.
Solution B
data Primitive = Any() | Void() | Int();
data Type = prim(Primitive p) | Not(Type l) | And(set[Type] es) | Or(set[Type] es);
Type reduce(Not(prim(Primitive p))) = prim(p);
default Type reduce(Type t ) = t;
Here the primitives are collected in a separate ADT Primitive
and they are included in Type
via the constructor prim
. Now reduce(Not(prim(Void())))
will reduce to prim(Void())
.
Final Notes
prim
as in Solution B) but for various technical reasons we did not include it. Although desirable, I am not sure that we will ever do.default
, they are the catch all case when the other declarations of a function do not match.public
, unless preceded by the key word private
.