在for循环中使用隐式参数会导致挂起

时间:2019-08-12 13:26:27

标签: raku

考虑以下代码

my $a = "AABBCCBGG";
say join "\n", do for $a.comb.squish {
  $a ~~ s/^ ($_+) //;
}

my $a = "AABBCCBGG";
say join "\n", do for $a.comb.squish -> $b {
  $a ~~ s/^ ($b+) //;
}

第一个永久挂起,而最后一个按预期执行。这是错误还是使用我不理解的隐式$ _时有更详细的信息?使用Rakudo Star 2019.03.01。

2 个答案:

答案 0 :(得分:9)

您使用$_的代码在道德上等同于:

/''+/

这将永远循环(因为空字符串''匹配了无数次)。

(好,我只显示了一个简单的匹配,并且$_必须分配或绑定到强制转换为字符串的某个值,否则将不会发生无限循环,因此您的代码必须经过处理使其循环两次,使其在道德上等同于上述内容,但这些都是红色鲱鱼。)

  

在使用我不理解的隐式$_时是否有一些更详细的信息?

来自the smartmatch doc

  

smartmatch运算符的左侧别名为$_

在代码中:

lhs ~~ rhs;

等效于:

$_ := lhs;
rhs.ACCEPTS(lhs);

我怀疑您没有考虑上述两行中的第一行。

(如果要避免这种主题化,只需单独使用第二行。 1

假设$_被分配了一个定义的非空字符串:

s/$_//;

总是更新$_为空字符串('')。

并且:

$a ~~ s/^ ($_+) //;

$_别名为$a,然后将$_$a都更新为空字符串。

因此,第二次在for循环中,~~再次将$_别名为$a,该别名现在包含一个空字符串,然后到达无限循环条件是我的答案始于此。

脚语

1 在下面的评论中,Jo要求为什么 ~~ 需要“主题化”(别名$_为lhs)。权威的答案大概存储在@Larry的集体大脑中,可以用the P6 design documents来最好地表达(在页面搜索中“ smart match”和“ smartmatch”似乎是问题所在)。但我会就此事写自己的想法。

首先,aiui,不需要 这样。

Aiui @Larry可能已经决定,依赖于当前主题的构造(我认为这意味着//s///和适当的例行调用)与P5一样。

以下是在P5(具有适当的编译指示)和P6中运行的一些代码:

my $a = 'a value';
$_ = 'another value';
say $a ~~ s/value/changed string/;
say $a;
say $_;

您期望结果如何?

在P5中:


a value
another changed string

在P6中:

「value」
a changed string
another value

P5保持$a不变,修改$_,然后将修改后的结果与原始$a进行比较,得出结论不匹配(因此,say $a ~~ ...行表示空行)。

P6在智能匹配期间将$_别名为$a ,将$a永久保留为s///,并恢复$_还原为之前的值。

如果我们坚持使用P5的方式,我们也将无法编写以下内容:

  • foo ~~ / ... /,如果foo与正则表达式匹配,则为真;

  • my $a = 'AA'; $a ~~ .uc,并且在这段代码之前或之后,不管$_的值是否为真;

  • foo ~~ .&bar匹配项,其中bar是期​​望参数的子项,我们希望它获得foo

与此同时,.ACCEPTS也可用。因此,这不像您不能做与P5一样的事情。只是,默认情况下,如果人们首先不接触P5,并且@Larry认为总体上是件好事,那么按照主题工作的结构可能就象人们可能期望的那样。 / p>

总而言之,乔,我听说P5做了您期望的工作,但是假设至少部分原因是您使用 P5并且您的期望基于在很大程度上考虑了它的作用,并在考虑了上述内容并给自己足够的时间来吸收它之后,想知道它是否仍然是您首选。我很乐意听到您关于一个月后的感觉的后续评论!

至少,这是我目前对此主题的想法。

答案 1 :(得分:4)

像往常一样,莱比的回答是正确的。我只添加一个小例子来证明他的话。

如果将示例更改为此:

my $a = "AABBCCBGG";
say join "\n", do for $a.comb.squish {
    say "Pre-s/// $_";
    $a ~~ s/^{say "Checking $_"} ($_+) //;
}

它将打印

Pre-s/// A
Checking AABBCCBGG
$a is 
Pre-s/// B
Checking 

然后挂起。在进入smartmatch之前,它会保留循环变量,但是一旦它进入smarmatch,它就会更改为正在进行smartmatch的内容,并且将整个字符串替换为空,因此$a是第二次迭代,它挂断了。

结论:仅在非常确定没有在其他地方使用主题变量时,才使用主题变量。