尝试分配给字符串+角色时,"无法分配给不可变值"

jjm*_*elo 6 iterator mixins perl6

Iterable doc页面中的示例开始

role DNA does Iterable {
  method iterator(){ self.comb.iterator }
};

my @a does DNA = 'GAATCC';
.say for @a; # OUTPUT: «G?A?A?T?C?C?» 
Run Code Online (Sandbox Code Playgroud)

我发现使用它声明它很奇怪@,因此我将其更改为声明字符串的自然方式$:

my $a does DNA = 'GAATCC';
Run Code Online (Sandbox Code Playgroud)

但是失败了,有些令人困惑的"无法分配给不可变的价值".无需现场指派,所以我们可以这样做:

my $a = 'GAATCC';
$a does DNA;
.say for $a;
Run Code Online (Sandbox Code Playgroud)

这只是为了以后留下混合.但这只是打印字符串,而不关注Iterablemixin.让我们明确地调用它:

.say for $a.iterator;
Run Code Online (Sandbox Code Playgroud)

它确实和以前一样,只是它打印了值$a.iterator,而没有实际调用函数:

<anon|69>.new
Run Code Online (Sandbox Code Playgroud)

这看起来像是在另一个问题中发生的事情.基线问题是我不明白Iterable真正做了什么角色,以及foriterator在什么时候以及何时调用某个对象.任何的想法?

Bra*_*ert 8

我不认为这条线符合你的想法:

my @a does DNA = 'GAATCC';
Run Code Online (Sandbox Code Playgroud)

它与:

my @a := [ 'GAATCC', ];
@a does DNA;
Run Code Online (Sandbox Code Playgroud)

基本上,.comb调用将数组强制转换为Str,并将其拆分为字符.


如果您改为这样做:

my @a = 'GAATCC' but DNA;
Run Code Online (Sandbox Code Playgroud)

这基本上是一样的

my @a := Seq.new(('GAATCC' but DNA).iterator).Array;
Run Code Online (Sandbox Code Playgroud)

请注意,@变量存储Positional值而不是Iterable值.


你想要的是

my $a = 'GAATCC' but DNA;

$a.map: &say;
Run Code Online (Sandbox Code Playgroud)

如果您希望能够使用for,则不能使用带有$sigil 的变量

my \a = 'GAATCC' but DNA;

.say for a;
Run Code Online (Sandbox Code Playgroud)

您可能想要添加Seq list Listetc方法DNA.

role DNA does Iterable {
  method iterator(){
    self.comb.iterator
  }
  method Seq(){
    Seq.new: self.iterator
  }
  method list(){
    # self.Seq.list
    List.from-iterator: self.iterator
  }
}

my $a = 'GAATCC' but DNA;
.say for @$a;
Run Code Online (Sandbox Code Playgroud)


rai*_*iph 6

你的问题的标题指向一个错误.这个答案涵盖了bug以及您提出的其他隐含和显式问题.

背景

失败了,有点令人困惑"无法分配给不可变的值".

我认为这是一个错误.让我们从一些有效的代码开始:

my $a = 42;
say $a;          # 42
say WHAT $a;     # (Int)               type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar)            type of VARIABLE currently BOUND to $a
$a = 42;         # works fine
Run Code Online (Sandbox Code Playgroud)

my声明中$a获取BOUND到一个新Scalar容器.甲Scalar容器通常隐藏本身.如果你问WHATtype $ais,你实际上得到的是当前已分配给Scalar的值的类型(它包含的值").您需要VAR访问容器 BOUND到$ a.分配=Scalar容器时,将指定的值复制容器中.

role foo {}
$a does foo;     # changes the VALUE currently ASSIGNED to $a
                 # (NOT the VARIABLE that is BOUND to $a)
say $a;          # 42                  mixed in `foo` role is invisible
say WHAT $a;     # (Int+{foo})         type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar)            type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99
Run Code Online (Sandbox Code Playgroud)

does混合的foo作用下转化成42.您仍然可以分配给$ a,因为它仍然绑定到a Scalar.

注意这两种用法如何does产生非常不同的效果:

my $a does foo;  # mixes `foo` into VARIABLE bound to $a
$a does foo;     # mixes `foo` into VALUE assigned to $a
Run Code Online (Sandbox Code Playgroud)

错误

$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a;          # Scalar+{foo}.new    VALUE currently ASSIGNED to $a
say WHAT $a;     # (Scalar+{foo})      type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo})      type of VARIABLE currently BOUND to $a

$a = 'uhoh';     # Cannot assign to an immutable value
Run Code Online (Sandbox Code Playgroud)

does混合物的foo作用下进入Scalar绑定到$一个.似乎Scalar带有mixin的a不再能成功地作为容器运行,并且赋值失败.

这在我看来就像一个bug.

my $b does foo;  # BINDS mixed in VARIABLE to $b
$b = 'uhoh';     # Cannot assign to an immutable value
Run Code Online (Sandbox Code Playgroud)

my $b does foo具有相同的结果,my $b; $b.VAR does foo;因此您得到与上面相同的问题.

你困惑的其他事情

my $a = 'GAATCC';
$a does DNA;
.say for $a;
Run Code Online (Sandbox Code Playgroud)

只是打印字符串,而不关注Iterablemixin.

因为$aVARIABLE仍然绑定到a Scalar(如上面的背景部分所述),现在具有DNA混合角色的VALUE 与决策过程for使用是否调用其参数的.iterator方法无关.

让我们明确地调用它...打印值$a.iterator,而不实际调用函数:

.say for $a.iterator;
Run Code Online (Sandbox Code Playgroud)

那么它确实会调用你DNA角色的.iterator方法.但是在你的角色方法返回的最后还有另一个 .iterator调用,所以你就是那个次要的.self.combDNAiterator.say.iterator

解决方案今天有效

我认为布拉德的答案很好地涵盖了你的大部分选择.

而且我觉得你的好does DNA要点,如果你想使用是因为它与今天的P6好得不能再好$印记.

一天可能有效的解决方案

在一个理想的世界中,P6设计中的所有甜蜜都将完全实现在6.cPerl 6的Rakudo编译器实现中.也许这包括编写这个并获得你想要的东西的能力:

class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;
Run Code Online (Sandbox Code Playgroud)

...代码与你在gist中的代码大致相同,只是DNA类是标量容器,因此该new方法将是一个STORE方法或类似的方法,将传递的值分配给$!value属性或某些值,如果值被分配到容器使用=.

但相反,你得到:

is trait on $-sigil variable not yet implemented. Sorry.
Run Code Online (Sandbox Code Playgroud)

因此,今天最接近理想的= 'string'变化$a就是:= DNA.new('string')像你在你的要点中那样使用绑定.

请注意,您可以结合的任意组合容器@%印记变量.所以你可以看到事情最终会如何发挥作用.