perl6 subs 真的是词法范围还是有额外的?

Posted

技术标签:

【中文标题】perl6 subs 真的是词法范围还是有额外的?【英文标题】:Are perl6 subs really lexically scoped or have extra? 【发布时间】:2019-06-26 17:43:35 【问题描述】:

如果我有如下块:


   say $myVar;
   my $myVar=1;


我得到了预期的错误:

Variable '$myVar' is not declared 

但是以类似的方式使用sub


    test();
    my sub test() 
        say "Hello";
    

这运行没有错误并打印:

Hello

$myVartest 在封闭块之外不可见,因此从这个意义上说,它们都是词法范围的。

sub 必须将其声明“提升”到块的顶部,因为 test 在其在代码中的位置之前已定义并可使用。但是,我找不到支持此内容的参考。

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

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

这确实引出了一个问题:perl6 subs 在这个意义上真的是词法范围的吗?

【问题讨论】:

下面是 Perl 5 的类似问题:Why subroutine needs to be written after the declaration of variables used in it?。我认为同样类型的推理也适用于 Perl 6。 【参考方案1】:

当 Perl6 遇到函数调用时,它会记下它,但不会检查函数是否存在。

所以下面会编译,但实际上不会工作。 (该函数在调用的地方不可用。)

foo 1;
my &foo = &say;

下面的编译器做了同样的事情,但是优化器意识到它甚至无法在任何地方找到对该函数的引用。 (所以优化器会导致它在编译过程中失败。)

bar 1;

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

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

没有必要要求它们在使用前被声明,所以限制被移除了。


在 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 

在 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 

【讨论】:

在这种情况下,我会考虑变量与代码的不同范围。我认为这让我感到困惑。您关于编译时间与运行时间的 cmets 帮助我解决了这个问题。谢谢【参考方案2】:

来自Subroutine Apocalypse:

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

【讨论】:

以上是关于perl6 subs 真的是词法范围还是有额外的?的主要内容,如果未能解决你的问题,请参考以下文章

15年,Perl 6真的要来了!

真的,Perl 6 发布了!!!——我们已经等了整整十五年!

词法范围的排序行为

Perl 6 真的太烦人了?

闭包.词法作用域#

Perl 词法范围变量在声明中的效率