在单个语句(Perl 5与Perl 6)中进行后增量和变量重用

Dav*_*man 9 perl perl6 undefined-behavior sequence-points raku

我天真地想在Perl 6和Perl 5之间进行相当多的字面上的翻译,实际上却没有,因为后增量变量的处理方式不同。

Perl 6产生了理想的结果,即幻方:[[8,1,6],[3,5,7],[4,9,2]]

my @sq; my $n = 3; my $i = 1; my $x = $n/2; my $y = 0;
@sq[($i%$n ?? $y-- !! $y++) % $n][($i%$n ?? $x++ !! $x) % $n] = $i++ for 0..$n**2 - 1;
say join ' ', $_ for @sq;
Run Code Online (Sandbox Code Playgroud)

Perl 5中的“相同”代码不:[[8,1,3],[9,5,7],[4,6,2]]

$n = 3; $i = 1; $x = $n/2; $y = 0;
$sq[($i%$n ? $y-- : $y++) % $n][($i%$n ? $x++ : $x) % $n] = $i++ for 0..$n**2 - 1;
say join ' ', @$_ for @sq;
Run Code Online (Sandbox Code Playgroud)

如果将语句拆分,则两者都可以正常工作,并且所有增量和减量都在赋值之后完成,例如在Perl 5中:

for (0 .. $n**2 - 1) {
    $sq[ $y%$n ][ $x%$n ] = $i;
    $i%$n ? $y-- : $y++;
    $x++ if $i%$n;
    $i++;
}
Run Code Online (Sandbox Code Playgroud)

如果递增或递减操作的返回值是该操作之前的变量的值,则Perl 5似乎是错误的。但是对代码进行的实验表明,$i%$n条件的结果是差异的源头,因此貌似Perl 6可能以$i无法严格保证的方式依赖的值。

因此,与Perl 5相比,Perl 6能够使我感到惊讶的是,不是吗?

mor*_*itz 9

如果您在单个语句中修改并读取相同的变量,则Perl 5和Perl 6均无法保证已定义行为。

Perl 6提要在并行执行的上下文中讨论序列点,但我相信它们也适用于语句内的读写问题。

但总的来说,您根本无法依靠任何一种语言来依赖它。


Håk*_*and 0

看来Perl 5和Perl 6代码之间的区别在于Perl 5代码使用了$i早于Perl 6的更新。例如以下Perl 5代码:

my $n = 3;
my $i = 2;
my $x = 5/2;
my $y = -1;
my @sq;
$sq[ ($i % $n ? $y-- : $y++) % $n] [ ($i % $n ? $x++ : $x) % $n ] = $i++;
say "x = $x, y = $y";
Run Code Online (Sandbox Code Playgroud)

印刷:

x = 2.5, y = 0
Run Code Online (Sandbox Code Playgroud)

而相同的 Perl 6 代码:

my $n = 3;
my $i = 2;
my $x = 5/2;
my $y = -1;
my @a;
@sq[ ($i % $n ?? $y-- !! $y++) % $n][ ($i % $n ?? $x++ !! $x) % $n ] = $i++;
say "x = $x, y = $y";
Run Code Online (Sandbox Code Playgroud)

印刷

x = 3.5, y = -2
Run Code Online (Sandbox Code Playgroud)

因此,Perl 5 代码使用$i++右侧的更新值(即在左侧$i = 3进行计算,而 Perl 6 使用旧值来计算等式左侧的索引。$i % $n$i = 2