Search code examples
rascal

Inheritance for Algebraic Data Types in Rascal?


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?


Solution

  • 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

    • We would also prefer to have inheritance (without the extra constructor 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.
    • Note the functions preceded by default, they are the catch all case when the other declarations of a function do not match.
    • All functions are public, unless preceded by the key word private.