使用捕获的类型来键入 class 的属性
Using captured types to type a class's attributes
我已按照 SO 问题的答案中的说明进行操作
How can classes be made parametric in Perl 6?。但是,我遇到了一些软障碍;我正在尝试使用类型捕获键入内部 class 的属性并收到以下错误:
Died with X::TypeCheck::Assignment
in submethod BUILDALL at ...
in method insert at ...
in block <unit> at ...
在下面的示例中,我输入了 class BinaryNode
的 $.item
属性(使用 T
),但这样做会导致上述错误:
class BinarySearchTree {
my role BTSImpl[::T] {
my class BinaryNode is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode.new(item => $x)
}
}
method ^parameterize(Mu:U \this, Mu \T) {
my $type := this.^mixin: BTSImpl[T];
$type.^set_name: this.^name ~ '[' ~ T.^name ~ ']';
$type
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
首先,几乎不需要执行 class
+ ^parameterize
+ role
技巧。它出现在一些内部结构中,因为它有助于处理一些自举问题(在根据自身定义语言时的那种乐趣)。但是,在普通的 Raku 代码中,只需编写参数 role
而不是 class
。从消费者的角度来看,通常没有区别;一罐:
- 对其调用
.new
以创建一个实例(这实际上创建了一个 class,称为 "pun",在幕后并创建了它的实例)
- 事实上,在类型对象上调用任何方法都得到相同的结果;
new
并不特别
- 从它继承(同样,它适用于自动生成的class)
还有额外的好处,有人也可以编写它而不是继承它。
其次,在 role
内部定义的 class
和封闭的 role
之间没有任何关系(这是一般原则:一个包嵌套在另一个包内不会' t 暗示它们之间在对象模型级别的任何关系)。因此我们需要使它单独通用并实例化它。
这两个让我们:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[T].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
这确实 应该 工作,但编译器似乎在 BinaryNode[T]
上弄错了时间。我们可以通过强制它延迟参数化直到运行时来解决这个问题;我们可以通过多种方式做到这一点,但编写 BinaryNode[$(T)]
紧凑且便宜(优化后几乎没有额外成本)。因此给出了一个可行的解决方案:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[$(T)].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
我已按照 SO 问题的答案中的说明进行操作 How can classes be made parametric in Perl 6?。但是,我遇到了一些软障碍;我正在尝试使用类型捕获键入内部 class 的属性并收到以下错误:
Died with X::TypeCheck::Assignment
in submethod BUILDALL at ...
in method insert at ...
in block <unit> at ...
在下面的示例中,我输入了 class BinaryNode
的 $.item
属性(使用 T
),但这样做会导致上述错误:
class BinarySearchTree {
my role BTSImpl[::T] {
my class BinaryNode is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode.new(item => $x)
}
}
method ^parameterize(Mu:U \this, Mu \T) {
my $type := this.^mixin: BTSImpl[T];
$type.^set_name: this.^name ~ '[' ~ T.^name ~ ']';
$type
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
首先,几乎不需要执行 class
+ ^parameterize
+ role
技巧。它出现在一些内部结构中,因为它有助于处理一些自举问题(在根据自身定义语言时的那种乐趣)。但是,在普通的 Raku 代码中,只需编写参数 role
而不是 class
。从消费者的角度来看,通常没有区别;一罐:
- 对其调用
.new
以创建一个实例(这实际上创建了一个 class,称为 "pun",在幕后并创建了它的实例) - 事实上,在类型对象上调用任何方法都得到相同的结果;
new
并不特别 - 从它继承(同样,它适用于自动生成的class)
还有额外的好处,有人也可以编写它而不是继承它。
其次,在 role
内部定义的 class
和封闭的 role
之间没有任何关系(这是一般原则:一个包嵌套在另一个包内不会' t 暗示它们之间在对象模型级别的任何关系)。因此我们需要使它单独通用并实例化它。
这两个让我们:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[T].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
这确实 应该 工作,但编译器似乎在 BinaryNode[T]
上弄错了时间。我们可以通过强制它延迟参数化直到运行时来解决这个问题;我们可以通过多种方式做到这一点,但编写 BinaryNode[$(T)]
紧凑且便宜(优化后几乎没有额外成本)。因此给出了一个可行的解决方案:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[$(T)].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);