【问题标题】:Which features of Perl make it a functional programming language?Perl 的哪些特性使它成为一种函数式编程语言?
【发布时间】:2015-06-25 09:27:53
【问题描述】:

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

我找到了:Higher Order Perl

这让我对 Perl 是一种函数式编程语言的断言感到好奇。现在,我意识到函数式编程是一种技术(很像面向对象)。

但是我找到了what makes a functional programming language的列表:

  • 一等函数
  • 高阶函数
  • 词法闭包
  • 模式匹配
  • 单个作业
  • 懒惰评估
  • 垃圾回收
  • 类型推断
  • 尾调用优化
  • 列表理解
  • 一元效应

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

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

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

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

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

【问题讨论】:

标签: perl functional-programming


【解决方案1】:

相关的有用的东西:

Perl monks rant about functional programming

Higher Order Perl

C2.com functional programming definitions

First Class functions

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

所以在 Perl 中:

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

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

do_something($print_something);

结论:本机支持

Higher Order Functions

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

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

  • 输出一个函数

参考this post on perlmonks

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

结论:本机支持

Lexical Closures

在 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->()

结论:本机支持

Pattern Matching

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

调度表是最接近的近似值 - 本质上是匿名子或代码参考的哈希。

use strict;
use warnings;

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

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

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

结论:解决方法

Single Assignment

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

我不确定perl 是否真的这样做了。最接近的近似值可能是引用/匿名潜艇或constant

判决:不支持

Lazy Evaluation

等到最后一刻才对表达式求值,尤其是为了优化可能不使用表达式值的算法。

Examples of lazy evaluation techniques in Perl 5?

再一次,回到Higher Order Perl(老实说,我与这本书无关——它似乎只是关于这个主题的关键文本之一)。

这里的核心概念似乎是 - 在 perl 中创建一个“链表”(使用面向对象的技术),但在“结束标记”处嵌入一个代码引用,以评估您是否能达到那一步。

结论:解决方法

Garbage Collection

“GarbageCollection(GC),又称自动内存管理,是堆内存的自动回收。”

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

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

结论:原生支持

Type Inference

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

Perl 确实会根据需要来回隐式转换值。通常这工作得很好,你不需要弄乱它。有时您需要通过显式数字或字符串操作来“强制”该过程。典型地,这是通过添加 0 或连接一个空字符串来实现的。

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

结论:原生支持

Tail Call Optimization

尾调用优化(或尾调用合并或尾调用消除)是 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 提供的更简洁的语法

判断:原生

List Comprehensions

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

Perl 有 mapgrepreduce

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

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

所以你可以:

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

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

Monadic effects

...不,仍然有这些问题。它比我想象的要简单得多或复杂得多。

如果有人有更多信息,请填写或编辑此帖子或...。我对所涉及的一些概念仍然很粗略,所以这篇文章更像是一个起点。

【讨论】:

  • 可能值得在每种情况下添加一个判断是否可以说 Perl 支持它。我不会计算模式匹配、惰性求值和类型推断,Perl 在语言级别不支持这些(你当然可以伪造它们或创建库,使其看起来像 Perl 原生拥有它们)。
  • 虽然所有这些特性都是函数式编程语言的典型特征,但很少有函数式语言特有的特性。而我认为的定义特征,即应用程序编程(一切都是函数,有副作用)完全缺失。另一个缺少的候选特征是eval(Perl 具有)和将结构化数据评估为代码的能力(Perl 缺乏的类似 Lisp 的eval,它的eval 适用于未分析的字符串)。
  • 还有一个是新语法的发明(例如可以用 Lisp 中的宏来完成); Perl 在这方面走了很长一段路,参见例如IO::All.
  • 术语type inference:通常保留给静态类型语言,其类型系统更类似于Perl 的类而不是Perl 的类型; Perl 类在编译时不存在,它们是在运行时创建的。 Perl 的类型强制完全不同,如果你问我,它更像是 C 之类的语言。
  • perl 支持尾调用。要么查看goto &sub 表示法,要么查看Sub::Call::Tail 提供的更简洁的语法。
【解决方案2】:

非常好的话题,我想写一篇题为“骆驼是功能性的”链接的文章。让我贡献一些代码。

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);
        }
}

【讨论】:

    猜你喜欢
    • 2010-09-09
    • 1970-01-01
    • 2011-07-17
    • 2010-09-28
    • 1970-01-01
    • 2023-04-09
    • 2010-09-17
    • 2011-04-04
    • 2011-03-30
    相关资源
    最近更新 更多