使用捕获的类型来键入类的属性

uzl*_*xxx 4 metaprogramming parametric-polymorphism raku

我已经按照 SO 问题如何在 Perl 6 中设置参数化类的答案中的 说明进行操作?. 但是,我遇到了一些软障碍。我正在尝试使用类型捕获键入内部类的属性并收到以下错误:

Died with X::TypeCheck::Assignment
  in submethod BUILDALL at ...
  in method insert at ...
  in block <unit> at ...
Run Code Online (Sandbox Code Playgroud)

在下面的示例中,我输入了 classBinaryNode$.item属性(with 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);
Run Code Online (Sandbox Code Playgroud)

Jon*_*ton 8

首先,有几乎无需进行class+ ^parameterize+role伎俩。它出现在一些内部结构中,因为它有助于处理一些引导问题(根据自身定义语言时那种乐趣)。但是,在普通的 Raku 代码中,只需编写一个参数role而不是class. 从消费者的角度来看,通常没有区别;一罐:

  • 调用.new它来创建一个实例(它实际上创建了一个类,称为“双关语”,在幕后制作它的实例)
  • 实际上,调用类型对象上的任何方法都具有相同的结果;new并不特别
  • 从它继承(同样,它适用于自动生成的类)

额外的好处是有人也可以编写它而不是继承。

其次,a 的class内部定义role和封闭之间没有关系role(这是一个一般原则:将一个包嵌套在另一个包中并不意味着它们之间在对象模型级别上有任何关系)。因此,我们需要使它单独通用并实例化它。

这两个让我们:

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);
Run Code Online (Sandbox Code Playgroud)

这确实应该有效,但编译器似乎在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);
Run Code Online (Sandbox Code Playgroud)