Perl提供的编译时功能是什么,其他语言没有?

时间:2010-08-26 13:35:26

标签: perl scripting programming-languages

Perl被认为是通用编程语言吗?

Wikipedia

上阅读
  

Perl有一个图灵完备语法,因为解析可能会受到编译阶段执行的运行时代码的影响。[41]因此,Perl无法通过直接的Lex / Yacc词法分析器/解析器组合进行解析。相反,解释器实现了自己的词法分析器,它与修改后的GNU bison解析器协调,以解决语言中的歧义。

     

通常说“只有Perl才能解析Perl”,这意味着只有Perl解释器(perl)才能解析Perl语言(Perl),但即便如此,这一点也不正确。因为Perl解释器可以在编译阶段模拟图灵机,所以需要决定停机问题以便在每种情况下完成解析。这是一个长期存在的结果,Halting问题是不可判定的,因此即使perl也不能总是解析Perl。 Perl做出了不寻常的选择,让用户可以在自己的编译阶段获得完整的编程能力。理论纯度方面的成本很高,但实际上的不便似乎很少见。

因此,它说尽管Perl拥有Turing完整徽章,但它与其他语言不同,因为它使“用户可以在自己的编译阶段访问其完整的编程功能”。那是什么意思? Perl在编译阶段为我提供的编程能力是什么?

3 个答案:

答案 0 :(得分:6)

没有任何其他语言的Perl功能。 Lisp可以做任何事情(Lisp是示例,在这里。)。因此,也许我们可以将问题缩小到Perl的特性,这使得广泛的行为变得容易。

  • BEGIN块(END块也是。),它们在编译期间改变行为。所以我可以编写Perl代码来改变要加载的模块的位置。

    即使以下代码可能也有不同的含义。

    use Frobnify;
    Frobnify->new->initialize;
    

    因为我可以更改Frobnify加载的位置:

    BEGIN { 
        if ( [ localtime ]->[6] == 2 ) { 
            s|^/var|/var/days/tuesday| foreach @INC;
        }
    }
    

    所以在星期二,我加载/var/days/tuesday/perl/lib/Frobnify.pm

  • Source Filters可以编程方式编辑将执行的代码。 (关于源过滤器的CAVEAT!)(粗略地和大致相当于LISP宏)

  • BEGIN块与@INC hooks一样。因为我可以在开头修改@INC以查看更改加载的内容。我可以在@INC数组的前面设置一个子程序来加载我想加载的任何东西。钩子可以接收加载Frobnify的请求并通过加载Defrobnify.pm来响应它。

  • 与此类似的是Symbol Manipuation。加载Defrobnify.pm后,我可以这样做:

    *Frobnify:: = \*Defrobnify::;
    

    现在Frobnify->new会创建一个Defrobnify对象!

答案 1 :(得分:4)

子例程原型是一个编译时功能,或多或少是Perl独有的。 Perl的许多内置函数在其参数(标量,列表,引用,代码块,捕获)上强加了特殊类型的上下文。原型是将某些功能移植到用户定义的子例程的一种方式。

例如,Perl允许您使用(&)原型有效地生成新的语法结构。这在Try::Tiny等模块中使用,可以在语言中添加trycatch个关键字:

    try {
            die "foo";
    } catch {
            warn "caught error: $_"; # not $@
    };

这是有效的,因为trycatch被声明为sub try (&;@) { ... }sub name {...}语法等同于BEGIN { *name = sub {...} },这意味着它具有编译时效果。在try的情况下,(&;@)原型告诉编译器,只要它看到标识符try,第一个参数必须是一个裸块,并且在块后面是一个可选列表

这只是原型的一个例子,他们可以做很多其他事情:

$  imposes scalar context on an argument
&  imposes code context on an argument
@  imposes list context on an argument
%  imposes list context (with an even number of elements)
*  imposes glob context on the argument 
\$ imposes scalar reference context
\@ imposes array reference context
   ... for the rest of the sigils

由于它们的强大功能(以及其他语言的缺失)原型可能会令人困惑,因此最好适度使用。 (就像Perl的其他高级功能一样)。

答案 2 :(得分:1)

简单的答案是BEGIN块提供了图灵完整性:

BEGIN {
    my $foo = turing_machine_simulator($program);
}
只要perl编译器看到它们,就会执行

BEGIN个块。这意味着可以要求编译器执行任意复杂度的任务。 Perl可以做任何事情,它可以在编译阶段完成。