Perl 的哪些特性使它成为一种函数式编程语言? [英] Which features of Perl make it a functional programming language?

查看:24
本文介绍了Perl 的哪些特性使它成为一种函数式编程语言?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我发现:高阶 Perl

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

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

  • 一流的功能
  • 高阶函数
  • 词法闭包
  • 模式匹配
  • 单一分配
  • 懒惰评估
  • 垃圾收集
  • 类型推断
  • 尾调用优化
  • 列表理解
  • 一元效应

现在我非常熟悉其中一些:

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

词法闭包甚至是常见问题解答的一部分:什么是闭包? - 这里可能有更好的文章:http://www.perl.com/pub/2002/05/29/closure.html

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

有人能帮我填空吗?Perl 可以轻松完成以上哪一项(并且有一个简单的示例)并且是否有失败的示例?

解决方案

相关的有用的东西:

Perl 僧侣对函数式编程的咆哮

高阶 Perl

C2.com 函数式编程定义

一级函数

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

在 Perl 中:

my $print_something = sub { print "Something
" };子做某事{我的 ($function) = @_;$function->();}do_something($print_something);

结论:本机支持

高阶函数

<块引用>

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

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

  • 输出一个函数

参考这篇关于 perlmonks 的帖子:

<块引用>

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

结论:本机支持

词法闭包

在 perl 常见问题解答中,我们对 什么是关闭?:

<块引用>

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

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

这可能在文章中解释得更清楚一些:实现闭包

sub make_hello_printer {我的 $message = "你好,世界!";返回子{打印$消息;}}我的 $print_hello = make_hello_printer();$print_hello->()

结论:本机支持

模式匹配

<块引用>

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

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

使用严格;使用警告;子 do_it {打印连接(:",@_);}我的 $dispatch = {'一件事' =>子{打印@_;},'another_thing' =>&do_it,};$dispatch->{'onething'}->("fish");

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

结论:解决方法

单一作业

<块引用>

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

我不确定 perl 真的能做到这一点.最接近的近似值可能是引用/匿名订阅或 constant.

结论:不支持

懒惰评估

<块引用>

等到最后一刻评估表达式,尤其是为了优化可能不使用表达式值的算法.

Perl 5 中的惰性求值技术示例?

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

这里的核心概念似乎是 - 在 perl 中创建一个链接列表"(使用面向对象的技术),但在您的结束标记"中嵌入一个代码引用,以评估您是否达到了那个程度.

结论:解决方法

垃圾收集

<块引用>

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

Perl 通过引用计数来实现这一点,并在不再被引用时释放它们.请注意,这可能会对您(可能!)在函数式编程时更可能遇到的某些事情产生影响.

特别是 - perldoc perlref

结论:原生支持

类型推断

<块引用>

TypeInference 是对程序的分析以推断某些或所有表达式的类型,通常在 CompileTime

Perl 会根据需要隐式地来回转换值.通常这很有效,您不需要弄乱它.有时,您需要通过进行显式数字或字符串操作来强制"该过程.规范地,这是通过添加 0 或连接一个空字符串.

您可以使用 dualvars

结论:原生支持

尾调用优化

<块引用>

尾调用优化(或尾调用合并或尾调用消除)是 TailRecursion 的概括:如果一个例程在返回之前做的最后一件事是调用另一个例程,而不是执行跳转和添加-stack-frame 紧随其后的是 pop-stack-frame-and-return-to-caller,简单地跳转到第二个例程的开头应该是安全的,让它重用第一个例程的堆栈帧(环境).

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

它会起作用,但如果您的递归深度 >100,它会发出警告.您可以通过添加以下内容禁用此功能:

没有警告'递归';

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

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

<块引用>

perl 支持尾调用.要么看到转到 ⊂符号,或查看由 Sub::Call::Tail

提供的更简洁的语法

结论:原生

列表理解

<块引用>

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

Perl 有 mapgrepreduce.

它还处理范围和重复的扩展:

my @letters = ( "a" .. "z" );

所以你可以:

my %letters = map { $_ =>1 } ( "A" .. "z" );

结论:原生(List::Utils 是一个核心模块)

一元效应

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

如果有人有更多信息,请加入或编辑这篇文章或……其他内容.我对所涉及的一些概念仍然很粗略,所以这篇文章更像是一个起点.

Inspired a little by: https://stackoverflow.com/questions/30977789/why-is-c-not-a-functional-programming-language

I found: Higher Order Perl

It made me wonder about the assertion that Perl is a functional programming language. Now, I appreciate that functional programming is a technique (much like object oriented).

However I've found a list of what makes a functional programming language:

  • First Class functions
  • Higher Order Functions
  • Lexical Closures
  • Pattern Matching
  • Single Assignment
  • Lazy Evaluation
  • Garbage Collection
  • Type Inference
  • Tail Call Optimization
  • List Comprehensions
  • Monadic effects

Now some of these I'm quite familiar with:

Garbage collection, for example, is Perl reference counting and releasing memory when no longer required.

Lexical closures are even part of the FAQ: What is a closure? - there's probably a better article here: http://www.perl.com/pub/2002/05/29/closure.html

But I start to get a bit fuzzy on some of these - List Comprehensions, for example - I think that's referring to map/grep (List::Util and reduce?)

I anyone able to help me fill in the blanks here? Which of the above can Perl do easily (and is there an easy example) and are there examples where it falls down?

解决方案

Useful things that are relevant:

Perl monks rant about functional programming

Higher Order Perl

C2.com functional programming definitions

First Class functions

In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. Specifically, this means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.

So in Perl:

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

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

do_something($print_something);

Verdict: Natively supported

Higher Order Functions

In mathematics and computer science, a higher-order function (also functional form, functional or functor) is a function that does at least one of the following:

  • takes one or more functions as an input

  • outputs a function

With reference to this post on perlmonks:

In Perl terminology, we often refer to them as callbacks, factories, and functions that return code refs (usually closures).

Verdict: Natively supported

Lexical Closures

Within the perl FAQ we have questions regarding What is a closure?:

Closure is a computer science term with a precise but hard-to-explain meaning. Usually, closures are implemented in Perl as anonymous subroutines with lasting references to lexical variables outside their own scopes. These lexicals magically refer to the variables that were around when the subroutine was defined (deep binding).

Closures are most often used in programming languages where you can have the return value of a function be itself a function, as you can in Perl.

This is explained perhaps a little more clearly in the article: Achieving Closure

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

my $print_hello = make_hello_printer();
$print_hello->()

Verdict: Natively supported

Pattern Matching

In the context of pure functional languages and of this page, Pattern Matching is a dispatch mechanism: choosing which variant of a function is the correct one to call. Inspired by standard mathematical notations.

Dispatch tables are the closest approximation - essentially a hash of either anonymous subs or code refs.

use strict;
use warnings;

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

$dispatch->{'onething'}->("fish");

Because it's just a hash, you can add code references and anonymous subroutines too. (Note - not entirely dissimilar to Object Oriented programming)

Verdict: Workaround

Single Assignment

Any assignment that changes an existing value (e.g. x := x + 1) is disallowed in purely functional languages.4 In functional programming, assignment is discouraged in favor of single assignment, also called initialization. Single assignment is an example of name binding and differs from assignment as described in this article in that it can only be done once, usually when the variable is created; no subsequent reassignment is allowed.

I'm not sure perl really does this. The closest approximation might be references/anonymous subs or perhaps constant.

Verdict: Not Supported

Lazy Evaluation

Waiting until the last possible moment to evaluate an expression, especially for the purpose of optimizing an algorithm that may not use the value of the expression.

Examples of lazy evaluation techniques in Perl 5?

And again, coming back to Higher Order Perl (I'm not affiliated with this book, honest - it just seems to be one of the key texts on the subject).

The core concept here seems to be - create a 'linked list' in perl (using object oriented techniques) but embed a code reference at your 'end marker' that evaluates if you ever get that far.

Verdict: Workaround

Garbage Collection

"GarbageCollection (GC), also known as automatic memory management, is the automatic recycling of heap memory."

Perl does this via reference counting, and releasing things when they are no longer referenced. Note that this can have implications for certain things that you're (probably!) more likely to encounter when functional programming.

Specifically - circular references which are covered in perldoc perlref

Verdict: Native support

Type Inference

TypeInference is the analysis of a program to infer the types of some or all expressions, usually at CompileTime

Perl does implicitly cast values back and forth as it needs to. Usually this works well enough that you don't need to mess with it. Occasionally you need to 'force' the process, by making an explicit numeric or string operation. Canonically, this is either by adding 0, or concatenating an empty string.

You can overload a scalar to do different things in by using dualvars

Verdict: Native support

Tail Call Optimization

Tail-call optimization (or tail-call merging or tail-call elimination) is a generalization of TailRecursion: If the last thing a routine does before it returns is call another routine, rather than doing a jump-and-add-stack-frame immediately followed by a pop-stack-frame-and-return-to-caller, it should be safe to simply jump to the start of the second routine, letting it re-use the first routine's stack frame (environment).

Why is Perl so afraid of "deep recursion"?

It'll work, but it'll warn if your recursion depth is >100. You can disable this by adding:

no warnings 'recursion';

But obviously - you need to be slightly cautious about recursion depth and memory footprint.

As far as I can tell, there isn't any particular optimisation and if you want to do something like this in an efficient fashion, you may need to (effectively) unroll your recursives and iterate instead.

Tailcalls are supported by perl. Either see the goto ⊂ notation, or see the neater syntax for it provided by Sub::Call::Tail

Verdict: Native

List Comprehensions

List comprehensions are a feature of many modern FunctionalProgrammingLanguages. Subject to certain rules, they provide a succinct notation for GeneratingElements? in a list. A list comprehension is SyntacticSugar for a combination of applications of the functions concat, map and filter

Perl has map, grep, reduce.

It also copes with expansion of ranges and repetitions:

my @letters = ( "a" .. "z" ); 

So you can:

my %letters = map { $_ => 1 } ( "A" .. "z" ); 

Verdict: Native (List::Utils is a core module)

Monadic effects

... nope, still having trouble with these. It's either much simpler or much more complex than I can grok.

If anyone's got anything more, please chip in or edit this post or ... something. I'm still a sketchy on some of the concepts involved, so this post is more a starting point.

这篇关于Perl 的哪些特性使它成为一种函数式编程语言?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆