Rascal 中代数数据类型的继承?

Inheritance for Algebraic Data Types in Rascal?

对,我在 Rascal 中有这样的数据类型:

data Type = Any() | Void() | Int() | Not(Type l) | And(set[Type] es) | Or(set[Type] es);

我想做的是像这样定义另一种类型:

data Primitive = Any() | Void() | Int();

然后可以做这样的事情:

Primitive p = Any();
Type d = p;

或者,例如,在简化 Type 时匹配 Primitive。像这样:

public Type reduce(Not(Primitive p)) = p;

目前,我能看到的唯一解决方案是像这样针对每种情况扩展上述规则:

public Type reduce(Not(Any)) = Any();
public Type reduce(Not(Void)) = Void();
public Type reduce(Not(Int)) = Int();

我猜想有一种方法可以做到这一点,但我还没有想出...想法?

问得好。 Rascal 没有用户定义的子类型,数据类型的类型是名义上的。这在理论上回答了你的问题,那么它在实践中是如何工作的呢?

  • 语法类型对数据类型的回答略有不同,所以下面是两个故事;
  • 有许多不同的习语可以用来对数据结构的层次结构进行建模,为了简单起见,我们在这里只展示三个;

这是一种使用新功能扩展数据类型的方法,不涉及添加新类型,这会生成一个与您预期的模型过于近似的模型:

// first the primitive types are defined (I've added Not here to make a point later):
data Type = Any() | Void() | Int() | Not(Type l); 

// then the extension is added (perhaps in a different module)
data Type = And(set[Type] es) | Or(set[Type] es);

// the second definition adds its alternatives also to the child of `Not`.

第二种方式更接近实际扩展,因为原来的Type没有扩展,也没有意外添加"junk":

// we give the original type a unique name:
data Primitive = Any() | Void() | Int();

// For the extension the Primitive type is not polluted with the new constructors, but
// it was wrapped inside a singleton constructor `prim`
data Type = prim(Primitive super) | And(set[Type] es) | Or(set[Type] es);

当然,第二个解决方案会让您在可能的模式匹配中添加 prim 构造函数,但 / 深度匹配运算符将允许您尽可能忽略它。例如:

bool evalt(prim(p)) = evalp(p);
bool evalp(Any()) = true;
bool evalp(Not(p)) = !evalp(p);

bool containsVoid(Type t) = /Void() := t; 

语法类型的情况类似,但由于语法类型中的链式规则是不可见的,因此它增加了一些额外的风味:

syntax Primitive = "any" | "void" | "int";

// notice the first chain rule or "injection" of Primitive into Type:
syntax Type = Primitive | left Type "∧" Type > left Type "∨" Type;

bool evalt((Type) `any`) = true; // the chain rule is parsed but invisible

人们一直在讨论将隐式链接也添加到抽象数据类型中,因为这样模拟子类型很有吸引力。我想这就像 Scala 的隐式函数。陪审团仍然没有定论。

简短的回答:尽管抽象数据类型可以扩展(即它们的定义可以跨模块扩展),但没有直接继承.

解决方法

解决方案 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;

此处 Type 的所有构造函数都在单个 ADT 中,谓词 isPrim 选择原语。例如,reduce(Not(Void())) 将减少到 Void()

方案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;

这里的基元被收集在一个单独的 ADT Primitive 中,它们通过构造函数 prim 包含在 Type 中。现在 reduce(Not(prim(Void()))) 将减少到 prim(Void())

最后的笔记

  • 我们也希望继承(没有额外的构造函数 prim,如 解决方案 B),但由于各种技术原因,我们没有包含它。虽然令人向往,但我不确定我们是否会这样做。
  • 注意前面有 default 的函数,它们是 catch all 函数的其他声明不匹配的情况。
  • 所有函数都是public,除非前面有关键字private