性状中的混合角色显然不起作用

时间:2019-05-01 07:58:15

标签: traits perl6

此示例取from roast,尽管已经存在8年了:

role doc { has $.doc is rw }

multi trait_mod:<is>(Variable $a, :$docced!) {
    $a does doc.new(doc => $docced);
}

my $dog is docced('barks');
say $dog.VAR;

这将返回Any,而没有任何角色的混合。尽管特质不会出错,但显然没有办法进入“ doc”部分。有想法吗?

2 个答案:

答案 0 :(得分:5)

(此答案基于@guifa的答案和JJ的评论。)

在可变特征中使用的习惯用法基本上是$var.var.VAR

虽然大声说起来听起来很有趣,但看起来也很疯狂。不是,但是至少需要解释,并且也许某种形式的认知/句法缓解。

以下是有关如何理解的简短版本:

  • $var作为trait参数的名称是有意义的,因为它绑定到Variable,即变量的编译器视图视图。

  • 需要
  • .var来访问给定编译器视角的变量的用户视角视图。

  • 如果变量是Scalar,那么还需要.VAR 来获取变量,而不是包含的值。 (如果它不是Scalar,则无害。)

有些解脱?

我将在一个月中更详细地说明上述内容,但首先,如何减轻负担?

也许我们可以引入一种新的Variable方法。但是,除非该方法的名称如此好,以至于根本不需要在答案的下一部分中使用.var.VAR咒语解释,否则这将是一个错误。

但是我怀疑这样的名字存在。我想出的每个名字都会使事情变得更糟。即使我们想出了一个完美的名字,充其量还是值得的。

您对原始示例的复杂性感到震惊。有一个$var.var.VAR特征,称为is特征。因此,也许需要一个例程来抽象这种复杂性和does。但是总有一些方法可以降低双重性状的复杂性,例如:

$var.var.VAR

role doc[$doc] { has $.doc is rw = $doc} my $dog does doc['barks']; say $dog.doc; # barks

的详细解释
  

但是$var.var.VAR已经是一个变量。为什么有这么多$vvar

的确。 VAR绑定到$v类的实例。这还不够吗?

否,因为Variable

  • 用于存储元数据关于变量的编译过程。 (也许它应该被称为Variable?只是在开玩笑。Metadata-About-A-Variable-Being-Compiled在特征签名中看起来不错,而且更改其名称也不会阻止我们使用和解释Variable这个习惯用法。)

  • 不是我们要寻找的机器人。我们需要该变量的用户视角。已经被声明和编译的代码,然后被用作用户代码的一部分。 (例如,$var.var.VAR行中的$dog。即使它是say $dog...,所以它还是在编译时运行的,BEGIN say $dog...仍会 指的是绑定到用户的视图容器或值的符号,而不是仅与数据相关的编译器的视图$dog实例em>变量。)

  • 使编译器和编写特质的人的工作更加轻松。但这要求特征编写者访问变量的用户视角,以访问或更改用户的视角。 Variable的{​​{1}}属性存储该用户的眼睛视图。 (我注意到,烘烤测试具有一个.var属性,您已省略了该属性。现在显然已将其重命名为Variable。我的猜测是,这是因为变量可能绑定到不可变值而不是容器,所以名称.container被认为具有误导性。)

那么,我们如何到达.var

让我们从原始代码的变体开始,然后继续。我将从.container切换到$var.var.VAR,然后从$dog行中删除@dog

.VAR

几乎有效。一个微小的更改,它会起作用:

say

我要做的就是在multi trait_mod:<is>(Variable $a, :$docced!) { $a does role { has $.doc = $docced } } my @dog is docced('barks'); say @dog.doc; # No such method 'doc' for invocant of type 'Array' 行中添加multi trait_mod:<is>(Variable $a, :$docced!) { $a.var does role { has $.doc = $docced } } my @dog is docced('barks'); say @dog.doc; # barks 。在您的原文中,该行正在修改变量的编译器视图,即绑定到.var的{​​{1}}对象。不会修改用户的视线视图,即绑定到... does role ...的{​​{1}}。

据我所知,现在对于数组和哈希之类的复数容器,一切都可以正常工作:

Variable

但是当我们尝试使用$a变量时:

Array

我们得到:

@dog

这是因为@dog[1] = 42; say @dog; # [(Any) 42] say @dog.doc; # barks 返回的是用户眼睛视图变量通常返回的内容。使用Scalar,您将获得my $dog is docced('barks'); 。但是使用Cannot use 'does' operator on a type object Any. ,您将得到.var包含的值。 (这是P6的基本方面。效果很好,但是您必须在这种情况下知道它。)

因此,要使它再次出现[em] ,我们还必须添加几个Array。对于Array以外的其他任何内容,Scalar都是“禁止操作”,因此对添加Scalar以外的其他案例没有任何危害:

.VAR

现在Scalar案例似乎也可以起作用:

.VAR

(出于相同的原因,我不得不在Scalar行中重新引入multi trait_mod:<is>(Variable $a, :$docced!) { $a.var.VAR does role { has $.doc = $docced } } 。)

如果一切都好,那将是答案的结束。

错误

但是有些东西坏了。如果我们尝试初始化Scalar变量:

my $dog is docced('barks');
say $dog.VAR.doc; # barks

我们会看到:

.VAR

如@guifa所述,I stumbled on a while back

  

似乎带有混入的say不再成功地充当容器,并且分配失败。在我看来,这目前似乎是一个错误。

答案 1 :(得分:3)

答案不令人满意,但是也许您可以从中获得进步

role doc { 
  has $.doc is rw;
}

multi trait_mod:<is>(Variable:D $v, :$docced!) {
  $v.var.VAR does doc;
  $v.var.VAR.doc = $docced;
}

say $dog;            # ↪︎ Scalar+{doc}.new(doc => "barks")
say $dog.doc;        # ↪︎ barks
$dog.doc = 'woofs';  #
say $dog;            # ↪︎ Scalar+{doc}.new(doc => "woofs")

不幸的是,这有些不对劲,应用特性似乎会使变量变得不可变。