Perl6子真的是在词法范围上还是有额外的?

drc*_*law 7 scope perl6

如果我有如下所示的代码块:

{
   say $myVar;
   my $myVar=1;
}

Run Code Online (Sandbox Code Playgroud)

我得到预期的错误:

Variable '$myVar' is not declared 
Run Code Online (Sandbox Code Playgroud)

但是,以类似的方式 sub

{
    test();
    my sub test() {
        say "Hello";
    }
}
Run Code Online (Sandbox Code Playgroud)

这运行没有错误并打印:

Hello
Run Code Online (Sandbox Code Playgroud)

两者$myVartest在封闭块之外都不可见,因此从某种意义上来说,它们都在词法范围内。

sub必须具有其声明“悬挂”于块的顶部,test在其中的代码位置之前定义的和可用的。但是,我找不到参考资料来支持这一点。

引发此问题的原因是查看my subsperl 中的词法作用域,这在上面第二种情况的perl版本中给出了“未定义的子例程”错误。以我对词汇范围的理解,这就是我所期望的。

我不加思索地使用它...编写一些测试代码,然后将其包装到sub文件底部的声明中,并从文件的较早部分调用子程序。一切正常!

它确实导致了一个问题:在这种意义上,perl6 subs真的在词法范围内吗?

Bra*_*ert 7

当Perl6遇到函数调用时,它将对其进行记录,但不会检查该函数是否存在。

因此,以下内容可以编译,但实际上不起作用。(该函数在调用它的位置不可用。)

foo 1;
my &foo = &say;
Run Code Online (Sandbox Code Playgroud)

下面,编译器执行相同的操作,但是优化器意识到,它甚至无法在任何地方找到对该函数的引用。(因此,优化器会导致其在编译期间失败。)

bar 1;
Run Code Online (Sandbox Code Playgroud)

与其他变量之间存在差异的原因是,很多时候您可能有一个函数依赖于另一个函数,或者您想将这些函数放在其余的代码之后。
同样,函数的代码通常在编译时就知道了,而变量的值直到赋值后才知道。(分配在运行时发生。)

基本上,人们倾向于使用变量和函数的方式是不同的,因此它们的工作方式略有不同。

无需要求在使用它们之前先声明它们,从而消除了限制。


在Perl5中,函数会根据其原型修改解析器,因此编译器需要先查看一个声明,然后才能使用该声明来知道应如何解析它们。

use v5.10;

sub foo ();
sub bar;

say foo + 1; # foo() + 1 # foo is compiled as a term/constant
say bar + 1; # bar( +1 )

sub foo () { 2 }
sub bar { $_[0] + 2 }
Run Code Online (Sandbox Code Playgroud)

在Perl6中,所有函数都像列表一样进行编译,因此无需要求将它们预先声明。

use v6;

# these two lines don't really change anything.
sub foo () {...}
sub bar ($) {...}


say foo + 1; # foo( +1 ) # optimization failure (too many arguments)
say bar + 1; # bar( +1 )

sub foo () { 2 }
sub bar ( $a ) { $a + 2 }
Run Code Online (Sandbox Code Playgroud)


Val*_*kas 5

从子例程启示录中

Perl 6还允许您将对子例程的声明推迟到文件的后面,但前提是延迟的声明声明要解析的子例程与解析列表运算符的方式一致。基本上,任何无法识别的“裸词”都假定为必须在当前编译单元末尾声明的临时列表运算符。