Perl的哪些功能使它成为一种函数式编程语言?

Sob*_*que 17 perl functional-programming

灵感来自:https://stackoverflow.com/questions/30977789/why-is-c-not-a-functional-programming-language

我发现:高阶Perl

这让我对Perl是一种函数式编程语言的断言感到疑惑.现在,我欣赏函数式编程是一种技术(很像面向对象).

但是我找到了一个函数式编程语言的列表:

  • 头等舱功能
  • 高阶函数
  • 词汇封闭
  • 模式匹配
  • 单一作业
  • 懒惰的评价
  • 垃圾收集
  • 类型推断
  • 尾调用优化
  • 列表理解
  • 单子效应

现在其中一些我很熟悉:

例如,垃圾收集是Perl引用计数,并在不再需要时释放内存.

词汇封闭甚至是FAQ的一部分:什么是封闭?- 这里可能有更好的文章:http://www.perl.com/pub/2002/05/29/closure.html

但是我开始对其中的一些感到有点模糊 - 例如列表理解 - 我认为这是指map/ grep(List::Utilreduce?)

我有人能帮我填补这里的空白吗?Perl可以轻松完成以上哪些操作(并且有一个简单的例子)并且有哪些例子可以解决它?

Sob*_*que 20

有用的东西:

Perl僧侣们对功能编程大肆宣扬

高阶Perl

C2.com函数式编程定义

头等舱功能

在计算机科学中,如果将编程语言视为一等公民,则称其具有一流的功能.具体来说,这意味着该语言支持将函数作为参数传递给其他函数,将它们作为其他函数的值返回,并将它们分配给变量或将它们存储在数据结构中.

在Perl中:

my $print_something = sub { print "Something\n" };

sub do_something {
    my ($function) = @_;
    $function->();
}

do_something($print_something);
Run Code Online (Sandbox Code Playgroud)

判决:本机支持

高阶函数

在数学和计算机科学中,高阶函数(也是函数形式,函数或函子)是至少执行以下任一操作的函数:

  • 将一个或多个函数作为输入

  • 输出一个功能

参照这个职位上perlmonks:

在Perl术语中,我们经常将它们称为回调,工厂和返回代码引用(通常是闭包)的函数.

判决:本机支持

词汇封闭

在perl FAQ中我们有以下问题What is a closure?:

闭包是一个计算机科学术语,具有精确但难以解释的含义.通常,闭包在Perl中作为匿名子例程实现,并且在其自己的作用域之外具有对词法变量的持久引用.这些词汇神奇地指的是定义子程序时的变量(深度绑定).

闭包最常用于编程语言中,您可以将函数的返回值本身作为函数,就像在Perl中一样.

在文章中可能会更清楚地解释这一点:实现关闭

sub make_hello_printer {
    my $message = "Hello, world!";
    return sub { print $message; }
}

my $print_hello = make_hello_printer();
$print_hello->()
Run Code Online (Sandbox Code Playgroud)

判决:本机支持

模式匹配

在纯函数语言和此页面的上下文中,模式匹配是一种调度机制:选择函数的哪个变体是正确的调用.受标准数学符号的启发.

调度表是最接近的近似值 - 本质上是匿名子代码或代码引用的散列.

use strict;
use warnings;

sub do_it {
    print join( ":", @_ );
}
my $dispatch = {
    'onething'      => sub { print @_; },
    'another_thing' => \&do_it,
};

$dispatch->{'onething'}->("fish");
Run Code Online (Sandbox Code Playgroud)

因为它是just一个哈希,你也可以添加代码引用和匿名子程序.(注意 - 与面向对象的编程并不完全不同)

判决:解决方法

单一作业

在纯函数式语言中不允许任何更改现有值的赋值(例如x:= x + 1).4在函数式编程中,不鼓励赋值给单个赋值,也称为初始化.单一赋值是名称绑定的一个示例,它与本文所述的赋值不同之处在于它通常只能创建一次,通常是在创建变量时; 不允许后续重新分配.

我不确定是不是perl真的这样做.最接近的近似可能是引用/匿名子或可能constant.

判决:不支持

懒惰的评价

等到最后可能的时刻来评估表达式,特别是为了优化可能不使用表达式值的算法.

Perl 5中的惰性评估技术示例?

再一次,回到高阶Perl(我不是这本书的附属,诚实 - 它似乎只是关于这个主题的关键文本之一).

这里的核心概念似乎是 - 在perl中创建一个'链表'(使用面向对象的技术),但在你的'结束标记'中嵌入一个代码引用,评估你是否已经达到目标.

判决:解决方法

垃圾收集

"GarbageCollection(GC),也称为自动内存管理,是堆内存的自动回收."

Perl通过引用计数执行此操作,并在不再引用它们时释放它们.请注意,这可能会影响您(可能!)在函数式编程时更有可能遇到的某些事情.

具体 - 涵盖的循环引用 perldoc perlref

判决:原生支持

类型推断

TypeInference是一个程序的分析,用于推断一些或所有表达式的类型,通常在CompileTime

Perl会根据需要隐式地来回转换值.通常这很好用,你不需要弄乱它.有时您需要通过进行显式数字或字符串操作来"强制"该过程.通常,这可以通过添加0或连接空字符串来实现.

您可以通过使用来重载标量以执行不同的操作 dualvars

判决:原生支持

尾调用优化

尾调用优化(或尾调用合并或尾调用消除)是TailRecursion的一般化:如果例程在返回之前做的最后一件事是调用另一个例程,而不是做一个跳转和添加堆栈帧紧接着是一个pop-stack-frame-and-return-to-calller,它应该是安全的,只需跳转到第二个例程的开头,让它重新使用第一个例程的堆栈帧(环境).

为什么Perl如此害怕"深度递归"?

它会工作,但如果您的递归深度> 100,它会发出警告.您可以通过添加:

no warnings 'recursion';
Run Code Online (Sandbox Code Playgroud)

但显然 - 你需要对递归深度和内存占用略微谨慎.

据我所知,没有任何特定的优化,如果你想以有效的方式做这样的事情,你可能需要(有效地)展开你的递归并迭代.

Perl支持Tailcalls.要么看到转到⊂符号,要么看到它提供的更整洁的语法Sub::Call::Tail

判决:原住民

列表理解

列表推导是许多现代FunctionalProgrammingLanguages的一个特征.根据某些规则,它们为GeneratingElements提供了简洁的表示法?在列表中.列表理解是SyntacticSugar,用于函数concat,map和filter的应用程序组合

Perl有map,grep,reduce.

它还可以应对范围和重复的扩展:

my @letters = ( "a" .. "z" ); 
Run Code Online (Sandbox Code Playgroud)

所以你可以:

my %letters = map { $_ => 1 } ( "A" .. "z" ); 
Run Code Online (Sandbox Code Playgroud)

判决:原生(List::Utils是一个核心模块)

单子效应

......不,仍然有这些问题.它要么比我能理解得简单得多,要么复杂得多.

如果有人有更多的东西,请填写或编辑这篇文章或......某事.我对所涉及的一些概念仍然很粗略,所以这篇文章更多的是一个起点.

  • 虽然所有这些功能都是函数式编程语言的典型特征,但几乎没有特定于函数式语言的功能.我会考虑定义的特征,即应用程序编程(一切都是函数,有副作用)完全缺失.另一个缺少的候选特性是`eval`(Perl有)和将结构化数据评估为代码的能力(类似于Lisp的`eval`,Perl缺乏,它的'eval`适用于未分析的字符串). (3认同)