相关的有用的东西:
Perl monks rant about functional programming
Higher Order Perl
C2.com functional programming definitions
在计算机科学中,如果将函数视为一等公民,则称编程语言具有一等函数。具体来说,这意味着该语言支持将函数作为参数传递给其他函数,将它们作为来自其他函数的值返回,并将它们分配给变量或将它们存储在数据结构中。
所以在 Perl 中:
my $print_something = sub { print "Something\n" };
sub do_something {
my ($function) = @_;
$function->();
}
do_something($print_something);
结论:本机支持
在数学和计算机科学中,高阶函数(也称为函数形式、泛函或函子)是至少执行以下操作之一的函数:
参考this post on perlmonks:
在 Perl 术语中,我们经常将它们称为回调、工厂和返回代码引用的函数(通常是闭包)。
结论:本机支持
在 perl 常见问题解答中,我们有关于 What is a closure? 的问题:
闭包是一个计算机科学术语,具有精确但难以解释的含义。通常,闭包在 Perl 中实现为匿名子例程,并在其自身范围之外对词法变量进行持久引用。这些词法神奇地引用了定义子程序时周围的变量(深度绑定)。
闭包最常用于编程语言中,您可以让函数的返回值本身就是一个函数,就像在 Perl 中一样。
这可能在文章中解释得更清楚一点:Achieving Closure
sub make_hello_printer {
my $message = "Hello, world!";
return sub { print $message; }
}
my $print_hello = make_hello_printer();
$print_hello->()
结论:本机支持
在纯函数式语言和本页的上下文中,模式匹配是一种调度机制:选择函数的哪个变体是正确调用的变体。受标准数学符号的启发。
调度表是最接近的近似值 - 本质上是匿名子或代码参考的哈希。
use strict;
use warnings;
sub do_it {
print join( ":", @_ );
}
my $dispatch = {
'onething' => sub { print @_; },
'another_thing' => \&do_it,
};
$dispatch->{'onething'}->("fish");
因为它是just 一个哈希,你也可以添加代码引用和匿名子例程。 (注意——与面向对象编程并不完全不同)
结论:解决方法
在纯函数式语言中不允许任何更改现有值的赋值(例如 x := x + 1)。4 在函数式编程中,不鼓励赋值,而支持单一赋值,也称为初始化。单次赋值是名称绑定的一个示例,与本文中描述的赋值不同,它只能执行一次,通常是在创建变量时;不允许后续重新分配。
我不确定perl 是否真的这样做了。最接近的近似值可能是引用/匿名潜艇或constant。
判决:不支持
等到最后一刻才对表达式求值,尤其是为了优化可能不使用表达式值的算法。
Examples of lazy evaluation techniques in Perl 5?
再一次,回到Higher Order Perl(老实说,我与这本书无关——它似乎只是关于这个主题的关键文本之一)。
这里的核心概念似乎是 - 在 perl 中创建一个“链表”(使用面向对象的技术),但在“结束标记”处嵌入一个代码引用,以评估您是否能达到那一步。
结论:解决方法
“GarbageCollection(GC),又称自动内存管理,是堆内存的自动回收。”
Perl 通过引用计数来做到这一点,并在它们不再被引用时释放它们。请注意,这可能会对您(可能!)在函数式编程时更可能遇到的某些事情产生影响。
具体来说 - perldoc perlref 中涵盖的循环引用
结论:原生支持
TypeInference 是对程序的分析,以推断某些或所有表达式的类型,通常在 CompileTime 进行
Perl 确实会根据需要来回隐式转换值。通常这工作得很好,你不需要弄乱它。有时您需要通过显式数字或字符串操作来“强制”该过程。典型地,这是通过添加 0 或连接一个空字符串来实现的。
您可以使用dualvars 重载标量以执行不同的操作
结论:原生支持
尾调用优化(或尾调用合并或尾调用消除)是 TailRecursion 的概括:如果例程在返回之前做的最后一件事是调用另一个例程,而不是执行跳转和添加- stack-frame 之后紧跟 pop-stack-frame-and-return-to-caller,简单地跳转到第二个例程的开头应该是安全的,让它重新使用第一个例程的堆栈帧(环境)。
Why is Perl so afraid of "deep recursion"?
它会起作用,但如果你的递归深度大于 100,它会发出警告。您可以通过添加禁用此功能:
no warnings 'recursion';
但显然 - 您需要对递归深度和内存占用稍微谨慎。
据我所知,没有任何特定的优化,如果你想以一种有效的方式做这样的事情,你可能需要(有效地)展开你的递归和迭代反而。
perl 支持尾调用。要么查看 goto ⊂ 符号,要么查看 Sub::Call::Tail 提供的更简洁的语法
判断:原生
列表推导是许多现代函数式编程语言的一个特性。根据某些规则,它们为 GeneratingElements? 提供简洁的符号?在一个列表中。
列表推导式是结合了函数 concat、map 和 filter 应用的 SyntacticSugar
Perl 有 map、grep、reduce。
它还应对范围和重复的扩展:
my @letters = ( "a" .. "z" );
所以你可以:
my %letters = map { $_ => 1 } ( "A" .. "z" );
结论:原生(List::Utils 是核心模块)
...不,仍然有这些问题。它比我想象的要简单得多或复杂得多。
如果有人有更多信息,请填写或编辑此帖子或...。我对所涉及的一些概念仍然很粗略,所以这篇文章更像是一个起点。