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

时间:2017-07-31 04:59:57

标签: loops for-loop perl6

在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祖先的期望不同?我没有在设计文档中看到这一点(但尝试在某个时候搜索“循环”)。我无法想出一个能让事情变得更轻松的例子。

在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出现在{之前,所以它不在“内部”。

然而,尖头块呢?

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

并且,子程序签名?

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

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

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

2 个答案:

答案 0 :(得分:6)

你可以把它想象成一个块就是创造一个词汇范围。

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数组中的索引 @a[*-1]不仅仅是将*-1作为特殊语法约束到数组索引,而只是一种创建lambda /闭包的方法,您可以在任何想要简单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的一般设计美学不相符的特征之一。我认为它可能更容易争论它的弃用和删除而不是它更特别的 (没有人主张将其删除)

答案 1 :(得分:4)

我看到这样的用例:

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等价物。

除此之外,我不知道。