Perl被认为是通用编程语言吗?
上阅读Perl有一个图灵完备语法,因为解析可能会受到编译阶段执行的运行时代码的影响。[41]因此,Perl无法通过直接的Lex / Yacc词法分析器/解析器组合进行解析。相反,解释器实现了自己的词法分析器,它与修改后的GNU bison解析器协调,以解决语言中的歧义。
通常说“只有Perl才能解析Perl”,这意味着只有Perl解释器(perl)才能解析Perl语言(Perl),但即便如此,这一点也不正确。因为Perl解释器可以在编译阶段模拟图灵机,所以需要决定停机问题以便在每种情况下完成解析。这是一个长期存在的结果,Halting问题是不可判定的,因此即使perl也不能总是解析Perl。 Perl做出了不寻常的选择,让用户可以在自己的编译阶段获得完整的编程能力。理论纯度方面的成本很高,但实际上的不便似乎很少见。
因此,它说尽管Perl拥有Turing完整徽章,但它与其他语言不同,因为它使“用户可以在自己的编译阶段访问其完整的编程功能”。那是什么意思? Perl在编译阶段为我提供的编程能力是什么?
答案 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等模块中使用,可以在语言中添加try
和catch
个关键字:
try {
die "foo";
} catch {
warn "caught error: $_"; # not $@
};
这是有效的,因为try
和catch
被声明为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可以做任何事情,它可以在编译阶段完成。