哪些Perl的特性使其成为一种函数式编程语言?
哪些Perl的特性使其成为一种函数式编程语言?
受以下链接的启发:https://stackoverflow.com/questions/30977789/why-is-c-not-a-functional-programming-language
我发现了:Higher Order Perl
这让我想到了Perl是一种函数式编程语言的说法。现在,我欣赏函数式编程作为一种技术(就像面向对象编程一样)。
但是,我找到了这样一份列表,列出了函数式编程语言的特点:
- 一级函数
- 高阶函数
- 词法闭包
- 模式匹配
- 单负载赋值
- 延迟计算
- 垃圾回收
- 类型推断
- 尾调用优化
- 列表理解
- Monad效应
现在,我对其中一些特点还比较熟悉:
例如,垃圾回收是通过Perl引用计数和释放内存的方式进行的。
词法闭包甚至是常见问题的一部分:什么是闭包?——这里也可能有更好的文章:http://www.perl.com/pub/2002/05/29/closure.html
但是,我对其中一些特点有点模糊——例如,列表理解,我认为这是指map
/grep
(List::Util
和reduce
?)
有人能帮我填写这里的空白吗?以上哪些是Perl可以轻松完成的(是否有简单的示例),是否有Perl无法胜任的情况?
真是个好主题,我想写一篇标题为“骆驼是实用的”的文章。让我用一些代码来贡献。
Perl也支持这种匿名函数,例如
sub check_config { my ( $class, $obj ) = @_; my $separator = ' > '; # Build message from class namespace. my $message = join $separator, ( split '::', $class ); # Use provided object $obj or # create an instance of class with defaults, provided by configuration. my $object = $obj || $class->new; # Return a Function. return sub { my $attribute = shift; # Compare attribute with configuration, # just to ensure it is read from there. is $object->config->{$attribute}, # Call attribute accessor so it is read from config, # and validated by type checking. $object->$attribute, # Build message with attribute. join $separator, ( $message, $attribute ); } } sub check_config_attributes { my ( $class, $obj ) = @_; return sub { my $attributes = shift; check_config( $class, $obj )->($_) for (@$attributes); } }
相关的有用的东西:
头等函数
在计算机科学中,如果一种编程语言将函数看作头等公民,则称该语言具有头等函数特性。具体而言,这意味着该语言支持将函数作为参数传递给其他函数,从其他函数中返回函数,将其分配给变量或将其存储在数据结构中。
所以在 Perl 中:
my $print_something = sub { print "Something\n" }; sub do_something { my ($function) = @_; $function->(); } do_something($print_something);
结论:原生支持
高阶函数
在数学和计算机科学中,高阶函数(也称为功能形式、函数或可调用对象)是一个函数,它至少执行以下操作之一:
将一项或多项函数作为输入
输出一个函数
在 Perl 术语中,我们经常将它们称为回调、工厂和返回代码引用的函数(通常是闭包)。
结论:原生支持
词法闭包
在 Perl FAQ 中,我们有关于什么是闭包?
的问题:
闭包是计算机科学术语,具有精确定义但难以解释的含义。通常,在 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");
因为它只是一个哈希表,所以您也可以添加代码引用和匿名子程序。(注意-与面向对象编程并没有完全不同)
结论:解决方法
单一赋值
在纯函数式语言中,不允许改变现有值的任何赋值(例如x:= x +1)。4在函数式编程中,赋值不被鼓励,而是倾向于单一赋值,也称为初始化。单一赋值是名称绑定的示例,在本文中与本文中描述的赋值不同,只能在变量创建时执行一次;不允许在随后的重新赋值。
我不确定
perl
是否真正做到了这一点。最接近的近似可能是引用/匿名子程序或constant
。结论:不支持
惰性求值
等待到最后一刻以评估表达式,特别是为了优化可能不使用表达式值的算法。
再次回到Higher Order Perl (我与此书无关,它似乎只是关于这个主题的关键文本之一)。
在这里的核心概念似乎是-在perl中创建一个'链接列表'(使用面向对象的技术),但在您的'结束标记'中嵌入一个代码引用,以便在您到达那里时进行评估。
结论:解决方法
垃圾收集
"垃圾收集(GC),也称为自动内存管理,是自动回收堆内存的过程。"
Perl通过引用计数来实现这一点,并在不再引用时释放它们。请注意,这可能对某些函数式编程时更容易遇到的某些事物产生影响。
具体而言-循环引用在
perldoc perlref
中介绍过。结论:内置支持
类型推断
类型推断是分析程序以推断某些或所有表达式的类型,通常在编译时进行。
Perl会按需要隐式转换值。通常情况下,这足以工作,你无需干涉它。但偶尔你需要“强制”该过程,通过进行显式的数字或字符串操作。经典做法是加0或连接空字符串。
你可以用
dualvars
来重载一个标量以执行不同的操作。结论:本地支持
尾递归优化
尾调用优化(或尾调用合并或尾调用消除)是尾递归的一般化:如果一个子程序在返回之前最后一件事情是调用另一个子程序,而不是立即进行跳转并添加堆栈帧,然后是弹出堆栈帧并返回给调用方,应该可以安全地直接跳转到第二个子程序的开始处,让它重用第一个子程序的堆栈帧(环境)。
它可以工作,但如果递归深度>100,则会发出警告。你可以通过添加以下内容来取消警告:
no warnings 'recursion';
但是,显然,你需要对递归深度和内存占用量保持谨慎。
据我所知,没有任何特定的优化,如果你想以有效的方式执行此类操作,则可能需要“展开”递归并代替使用迭代。
Perl支持尾调用。请参阅goto⊂符号或查看
Sub::Call::Tail
提供的更优美的语法。结论:本地支持
列表推导式
列表推导式是许多现代函数式编程语言的特性。在一定规则的情况下,它们提供了一个简洁的表示法来生成列表中的元素。列表推导式是concat,map和filter函数的语法糖组合。
Perl有
map
、grep
、reduce
。它还处理范围和重复扩展:
my @letters = ( "a" .. "z" );
所以你可以:
my %letters = map { $_ => 1 } ( "A" .. "z" );
结论:本地支持(
List::Utils
是核心模块)单子效应
...不,我还是对这些有些困惑。它可能比我理解的要简单或更复杂。如果有人有更多信息,请加入或编辑此帖子或…一些别的什么。对于涉及的某些概念,我仍然感到模糊,因此这篇文章更多地是一个起点。