在正则表达式上调用Bool无法正常工作

jjm*_*elo 5 regex oop perl6

根据文档,类的Bool方法Regex...

与调用者的$ _变量匹配,对于匹配项返回True,对于不匹配项返回False。

但是,在这个例子中

$_ = "3";
my regex decimal { \d };
say &decimal.Bool;
Run Code Online (Sandbox Code Playgroud)

返回False。另外,查看源代码,它说的还算合理,因为它将匹配$!topic实例变量。但是,尚不清楚此变量将有效地对应于$ _,并且上面的示例似乎是这样说的。任何实际发生的想法?

Jon*_*ton 9

简短的答案:该文档对于6.c来说是准确的,但是确切的语义并不像“调用者”那样简单(实际上,它存在真正奇怪的错误的风险)。改进的行为是:

  • 用诸如/.../和这样的形式构造的匿名正则表达式rx:i/.../将捕获$_$/,并在代码到达它们的位置(填充$!topic问题中提到的变量)。
  • Bool并且sink会引起对所捕获的匹配$_,并且将所得到的存储Match对象成$/,只要它是可写的。

由于此行为仅适用于匿名正则表达式,因此您需要编写:

$_ = "3";
my regex decimal { \d };
say /<&decimal>/.Bool;
Run Code Online (Sandbox Code Playgroud)

这是很长的答案。首先,Bool-causes-matching行为的目的是为了使这样的事情起作用:

for $file-handle.lines {
    .say if /^ \d+ ':'/;
}
Run Code Online (Sandbox Code Playgroud)

在这里,for循环将填充topic变量$_,并if提供一个布尔上下文。最初的设计是.Bool查看$_调用方的。但是,这存在许多问题。考虑:

for $file-handle.lines {
    .say if not /^ \d+ ':'/;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,not是主叫方.BoolRegex。但是,not也将有其自己的$_-与任何子例程中一样-将其初始化为Any。因此,从理论上讲,匹配将不起作用。除此之外,因为实际实现的是遍历调用方,直到找到$_包含定义值的!这听起来很糟糕。考虑如下情况:

sub foo() {
    $_ = some-call-that-might-return-an-undefiend-value();
    if /(\d+)/ {
        # do stuff
    }
}
$_ = 'abc123';
foo();
Run Code Online (Sandbox Code Playgroud)

如果内部的调用foo返回一个未定义的值(也许是意外的),匹配将继续遍历调用者链,而$_在的调用者中找到的值foo。实际上,我们可以在调用堆栈中走很多个台阶!(此外:是的,这也意味着存在复杂的$/结果,需要更新!)

先前的行为还要求$_具有动态范围-即可供调用者查找。但是,具有动态作用域的变量会阻止大量分析(包括编译器和程序员的分析),因而无法进行优化。由于使用了很多习惯用法$_,这似乎是不可取的(没有人希望看到Perl 6性能指南建议“不要with foo() { .bar }在热代码中使用,with foo() -> $x { $x.bar }而要使用”)。因此,6.d更改$_为常规词汇变量。

这6.D $_作用域变化已经相当小现实世界的后果,但它确实事业的语义.Bool.sinkRegex进行检查,因为他们经常使用的东西的一个上依赖$_是动态的。这反过来揭示了$_我刚刚描述的“第一个定义的”行为-在这一点上,动态作用域的使用开始看起来更多是危险而不是好处!

新的语义意味着程序员编写一个匿名的正则表达式可以依靠它匹配$_和更新$/是在范围内可见他们写的正则表达式-这似乎很简单的解释,和-的情况下,他们最终以$_这ISN”定义-不足为奇!