perl6 rakudo 2016.11 匹配尝试分配给只读变量,为什么不在 2016.07 中?

perl6 rakudo 2016.11 match tries to assign to read-only variable, why not in 2016.07?

我在 Rakudo 2016.07 中运行良好的操作 class 中有以下方法,但我刚刚安装了 2016.11,现在新的 Rakudo 说我的方法试图分配给只读变量,我只是没看出问题:

method ptName ($/) { 
    my $nameStr = $/.Str, my $lastName, my $firstName; 
    my $newMatch  # this is line 182; 
                  # Cannot assign to a readonly variable or a value
       = $nameStr.match(/ \" (<alpha>+) .*? \, \s* (<alpha>+) .*? \" /);
    $lastName  = $newMatch[0];
    $firstName = $newMatch[1];
    make "$lastName $firstName"; 
}

整个错误信息是

Cannot assign to a readonly variable or a value
  in method ptName at /home/lisprog/Binary/grammar.pl line 182
  in regex ptName at /home/lisprog/Binary/grammar.pl line 151
  in regex TOP at /home/lisprog/Binary/grammar.pl line 137
  in block <unit> at /home/lisprog/Binary/grammar.pl line 217

哪些语言规范发生了变化?请帮忙。谢谢

============================================= ========

谢谢 raiph、Christoph、ZZ !!我不知道如何使用正确的格式添加长评论。所以,我正在为我自己的 post 添加评论。

我写了一个测试程序,现在看来,如果在方法签名中不使用($/),因为我必须在方法内部使用.match,我就不能再做任何事情了。我做错了什么?这是测试程序和结果:

测试程序:

grammar test {
    regex TOP   { <foo><bar> }
    regex foo   { :i \s* foo \s* }
    regex bar   { :i \s  bar \s* }
}

class actTest {
    method foo ($x) { # program fails if I use $/ in signature
      print "1 "; say $x; # how to combine the 2 and show $x as match?
      print "2 "; say $x.WHAT;
      my $newStr = $x.Str;
      print "3 "; say $newStr;
      my $newMatch 
           = $newStr.match(/:i(f)(oo)/); # adverb cannot be outside?
      print "4 "; say $newMatch.WHAT;
      print "5 "; say $newMatch;
      print "6 "; say $/;
      my $oo = $newMatch[1].Str;
      print "10 "; say $oo;
      my $f = $newMatch[0].Str;
      print "11 "; say $f;
      my $result = $oo ~ $f;
      print "12 "; say $result;
      make $result; # now I cannot make anything; huh???
    }
    method TOP ($/) { 
      print "8 "; say $<bar>;
      print "9 "; say $<foo>.made; # failed, method 'foo' makes nothing
      make $<bar> ~ $<foo>.made; 
    }
}

my $m = test.parse("Foo bar", actions => actTest.new);
print "7 "; say $m;

结果:

1 「Foo 」
2 (Match)
3 Foo 
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
11 F
12 ooF
1 「Foo」
2 (Match)
3 Foo
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
11 F
12 ooF
8 「 bar」
9 (Any)
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to
something meaningful.
in method TOP at matchTest.pl line 28
7 「Foo bar」
 foo => 「Foo」
 bar => 「 bar」

根据 git blame src/core/Str.pm,lizmat 在 10 月份进行了此工作。 Str.match 现在将 fiddle 与调用块的词法 $/ 一起使用,而以前显然没有这样做。

这意味着 Str.match 将 return 它的结果两次:第一次作为它的 return 值,第二次通过设置 $/ 带外。虽然通过 ~~ 的正则表达式应用程序也这样做(这是必要的,因此您可以使用 [=16=]$<foo> 之类的语法糖),但我不相信 Str.match 应该这样做。 如果它以前没有这样做,我怀疑它可能是一个错误:要么这样报告它,要么在 Freenode 上的 #perl6 中询问它。

正如 Zoffix 指出的那样,这是错误的旧行为,因为 $/ 总是应该设置,但无法这样做并没有触发异常。

这里有两个问题,我会依次回答:

1) match tries to assign to read-only variable

它尝试将 $/ 设置为只读,您已经在您的范围内。您可以简单地在语法的 $/ 的签名中使用不同的名称。我看到你马上将它强制转换为 Str,所以为什么不让签名这样做:

method ptName (Str() $nameStr) { ... }

2) why not in 2016.07?

新行为不是错误,核心团队决定当前的行为是可取的 (编辑:实际上,在进一步检查中它出现旧的行为是一个错误,如果它是只读的,.match 静默地设置 $/ 失败。

所以更大的问题是为什么行为会完全改变?

虽然保持行为不变以便用户可以依赖它是一个明显的目标,但我们还需要改进内容并继续前进。它的工作方式是我们有一个 huge test suite we call Roast。如果对代码进行的更改破坏了测试,则该更改不能在当前语言中进行,必须推迟到下一个语言版本发布(从那时起,用户可以使用 use v6.c 或其他任何方式来保持旧行为)。

但是,如果测试套件通过,则意味着更改尚未确定,我们可以更改它而无需等待下一个语言版本。这里就是这种情况,.match.

显然,我们不希望我们的用户翻阅我们的测试套件以寻找已测试的内容和未测试的内容,这就是为什么我们的文档遵循我们不记录未包含的内容的政策烤肉。

目前您使用的 .match 方法就是这种情况。我不确定你是从哪里了解到的,因为在 9 月底 I created a doc Issue 表明 .match 没有记录,所以它当时不在文档中并且正在等待大修 lizmat 工作上,这改变了咬你的行为。

所以我希望这能回答一些问题。我确实理解这样的代码破坏是非常不幸的,我们希望尽可能少地发生这种情况,但与此同时我们需要改进语言。希望随着实施的成熟,​​这些未经测试和未记录的功能会越来越少。

干杯, ZZ

感谢 ZZ、Christoph、raiph 和 smls 对我的帮助。我的问题已通过以下方式解决:

  1. 使用 $/ 以外的方法签名,并且
  2. 使用签名匹配对象制作而不是使用 $/ 制作。

另请参考答案:

您还可以使用 immediately-invoked lambda:-> $x { my $/; $x.match(/regex/) }($/)