为什么 Perl 6 的循环变量声明在外部范围?

Why is Perl 6's loop variable declaration in the outer scope?

在 Perl 6 中,以 for-style loop 声明的变量在外部范围内。这有效 is documented.

loop ( my $n = 0; $n < 3; $n++ ) {
    put $n;
    }

say "Outside: $n";

$n 在块外可见:

0
1
2
Outside: 3

这里是否有一个激励技巧使它不同于人们对 Perl 6 的祖先的期望?我没有在设计文档中看到对此的提及(但有时尝试搜索 "loop")。我无法想出一个可以让事情变得更简单的例子。

在 Perl 5 中,同样的事情是严格错误:

use v5.10;
use strict;

for ( my $n = 0; $n < 3; $n++ ) {
    put $n;
    }

say "Outside: $n";  # Nope!

并且,在 C 中(允许您这样做的那些),这是一个类似的错误:

#include <stdio.h>

int main () {

   for( int a = 10; a < 20; a = a + 1 ){
      printf("value of a: %d\n", a);
   }

   printf("value of a: %d\n", a);  /* Nope! */

   return 0;
}

像往常一样,我对解决方法不感兴趣。我知道怎么做。


正如我在评论中指出的那样,Synopsis 4 推动实现仅在词法出现的块内声明词法。

$n 出现在 { 之前,所以它不是 "inside" 块。

但是,尖块呢?

-> $a { put "a is $a" }

还有,子程序签名?

sub ( $a ) { put "a is $a" }

这些变量首先在 { 之前键入。

我不是特别关心这个,但如果我必须通过说你必须在你将使用它们的块中声明词法变量来解释这种打破传统的做法,有人可以指出这些情况。

我看到这样的用例:

loop ( my $n = 0; $n < 3; $n++ ) {
    put $n;
    last if 2.rand.Int;  # some run-time condition
}
say $n == 3 ?? 'Completed' !! 'Aborted';

这很难做到:

for ^3 -> $n {
}

相当于 for

除此之外,我不知道。

您可以将其视为创建词法作用域的块。

if (1) {
  my $a = 1;
}
$a;  # error
if (my $a = 1) {
}
$a;  # no error
loop (my $a = 1; $a == 1; ++$a) {
}
$a;  # no error

只是其他类 C 语言特例了(C 风格)for 循环,而 Perl 6 的设计是尽可能少的特例。

所以如果一个东西在一个地方非常有用,那么它应该被设计成在任何地方都可用。


例如 -1 在数组中建立索引。
*-1 不仅仅是将 @a[*-1] 作为限制数组索引的特殊语法,它只是一种创建 lambda/closure 的方法,您可以在任何需要简单 lambda 的地方使用它。

另一个例子是尖块不仅仅是在 for 循环中声明迭代变量的一种方式。

for @a -> $value {…}

它们可用于任何类似的结构。

if $a.some-resource-expensive-op -> $result {…}

而不是

{
  # note that $result isn't read-only like it is above
  my $result = $a.some-resource-expensive-op;
  if $result {…}
}

您甚至可以将它用作创建 lambda 的另一种语法。

@a.sort: -> $value {…}

为了使语言更易于推理,特殊情况需要发挥自己的作用,并且只有 loop 构造的参数,没有其他构造,只是块的一部分没有。
如果普遍有用那就不一样了

此外,loop 构造是少数几个不符合 Perl 6 的一般设计美学的功能之一。我认为争论它的弃用和删除可能比争论它更容易更特殊的情况。
(没有人主张删除)