Perl 提供了哪些其他语言没有的编译时功能?

发布于 2024-09-16 06:32:28 字数 689 浏览 0 评论 0原文

Perl 被视为通用编程语言吗?

上阅读有关它的内容维基百科

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

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

因此,它说虽然 Perl 拥有图灵完备徽章,但它与其他语言不同,因为“用户可以在自己的编译阶段访问其完整的编程能力”。这意味着什么? Perl 在编译阶段为我提供了哪些其他人没有提供的编程能力?

Is Perl considered a general purpose programming language?

Reading about it on Wikipedia

Perl has a Turing-complete grammar because parsing can be affected by run-time code executed during the compile phase.[41] Therefore, Perl cannot be parsed by a straight Lex/Yacc lexer/parser combination. Instead, the interpreter implements its own lexer, which coordinates with a modified GNU bison parser to resolve ambiguities in the language.

It is often said that "Only perl can parse Perl," meaning that only the Perl interpreter (perl) can parse the Perl language (Perl), but even this is not, in general, true. Because the Perl interpreter can simulate a Turing machine during its compile phase, it would need to decide the Halting Problem in order to complete parsing in every case. It's a long-standing result that the Halting Problem is undecidable, and therefore not even perl can always parse Perl. Perl makes the unusual choice of giving the user access to its full programming power in its own compile phase. The cost in terms of theoretical purity is high, but practical inconvenience seems to be rare.

So, it says that though Perl has the Turing complete badge, it is different from other languages because gives "the user access to its full programming power in its own compile phase". What does that mean? What programming power does Perl provide me at compiling phase that others don't?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不交电费瞎发啥光 2024-09-23 06:32:28

Perl 的所有功能都出现在任何其他语言中。 Lisp 可以做任何事情(Lisp 是一个例子,这里。)。因此,也许我们可以将问题缩小到 Perl 的哪些特性使得广泛的行为波动变得很容易。

  • 开始块(也是 END 块)会改变编译期间的行为。因此我可以编写 Perl 代码来更改要加载的模块的位置。

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

    使用 Frobnify;
    Frobnify->新建->初始化;
    

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

    <前><代码>开始{
    if ( [当地时间]->[6] == 2 ) {
    s|^/var|/var/days/tuesday| foreach @INC;
    }
    }

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

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

  • BEGIN 块一起的是 @INC 挂钩。因为我可以在开始时修改 @INC 来查看加载内容的变化。我可以在 @INC 数组的前面设置一个子例程来加载我想要加载的任何内容。该挂钩可以接收加载 Frobnify 的请求,并通过加载 Defrobnify.pm 来响应该请求。

  • 与此相伴的是符号操作。加载 Defrobnify.pm 后,我可以执行以下操作:

    *Frobnify:: = \*Defrobnify::;
    

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

There are no features of Perl that do not appear in any other language. Lisp can do anything (Lisp is an example, here.). So perhaps we can narrow the question down to what are the features of Perl that make wide behavior swings an easy thing to do.

  • BEGIN blocks (END blocks, too.) which alter the behavior during compile. So I can write Perl code that changes the location of modules to be loaded.

    Even the following code might have a different meaning.

    use Frobnify;
    Frobnify->new->initialize;
    

    Because I could have changed where Frobnify loads from:

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

    So on Tuesdays, I load /var/days/tuesday/perl/lib/Frobnify.pm

  • Source Filters can programmatically edit the code that will perform. (CAVEAT on source filters!) (crudely and roughly equivalent to LISP macros)

  • Somewhat along with BEGIN blocks are @INC hooks. As I can modify @INC at the beginning to see change what gets loaded. I can set a subroutine at the front of the @INC array to load anything I want to load. The hook can receive a request to load Frobnify and respond to it by loading Defrobnify.pm.

  • Somewhat along with this is Symbol Manipuation. After loading Defrobnify.pm, I can do this:

    *Frobnify:: = \*Defrobnify::;
    

    Now Frobnify->new creates a Defrobnify object!

冬天旳寂寞 2024-09-23 06:32:28

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

例如,Perl 允许您使用 (&) 原型有效地生成新的语法结构。这用于 Try::Tiny 等模块中添加 try< /code> 和 catch 语言关键字:

    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 的所有其他高级功能一样)。

Subroutine prototypes are a compile time feature that is more or less exclusive to Perl. Many of Perl's builtin functions impose special types of context on their arguments (scalar, list, reference, code-block, capture). Prototypes are a way of porting some of that functionality over to user defined subroutines.

For example, Perl allows you to effectively generate new syntactic constructs with the (&) prototype. This is used in modules like Try::Tiny to add try and catch keywords to the language:

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

This works because try and catch are declared as sub try (&;@) { ... }. The sub name {...} syntax is equivalent to BEGIN { *name = sub {...} } which means it has a compile time effect. In the case of try, the (&;@) prototype tells the compiler that any time it sees the identifier try, the first argument must be a bare block, and following the block is an optional list.

This is just one example of prototypes, and they are able to do many other things:

$  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

Due to their power (and absence in other languages) prototypes can be confusing and are best used in moderation. (like every other advanced feature of Perl).

尬尬 2024-09-23 06:32:28

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

BEGIN {
    my $foo = turing_machine_simulator($program);
}

BEGIN 块在 Perl 编译器看到它们后立即执行。这意味着可以要求编译器执行任意复杂度的任务。 Perl 能做的任何事情,它都可以在编译阶段完成。

The simple answer is that BEGIN blocks provide Turing-completeness:

BEGIN {
    my $foo = turing_machine_simulator($program);
}

BEGIN blocks are executed as soon as the perl compiler sees them. This means that the compiler can be asked to do tasks of arbitrary complexity. Anything Perl can do, it can do during its compilation phase.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文