计算机语言设计:列表的理解以及为什么它是有害的

443 查看

本文将列举不同编程语言的几个小例子,尝试解释什么是列表解析。并且试图宣扬我的观点:“列表解析”不论从概念上还是技术上,完全是函数式编程的一根阑尾——多余而且某种程度上还是有害的。

何为列表解析?

以python中的列表解析为例:

它产生一个0到8的列表,将奇数从该列表中移除,最后将剩余元素乘2,最后返回所得列表。

Python的列表解析(LC)的语法如下:

总而言之,这种特殊语法产生一个列表,并且允许程序员对其中元素进行过滤,以及将其中元素作为参数传给一个函数,但是所有这些都已“表达式”的形式出现。

(译者注:这个语法本身也是一个“表达式”,所以可以嵌套使用。)

 

列表解析的函数式的写法是这样的:

其他语言的列表解析是相似的。这儿有几个来自维基百科的例子。在下面的例子里,x^2>3作为条件,然后把每个元素乘以2返回结果.

Haskell

F#

OCaml

Clojure

Common Lisp

Erlang

Scala

这里是维基百科对
List comprehension
的解释,引用如下:

A list comprehension is a 
syntactic construct
 available in some programming languages for creating a list based on existing lists.

列表理解(LC)有以下特征:

*1.一个直接的列表生成器,可以对元素进行过滤,并且对每个元素应用一个函数

*2.是某些语言里面的特殊语法

*3.这种语法是一个单独的表达式,而不是由单独的函数组成

为什么列表理解是有害的?

  • 列表理解就像一个不透明的俚语一样,它妨碍沟通,造成误会
  • 列表理解是编程里面一个冗余的概念。它只是一个简单的列表生成器。他可以被简单的功能函数formmap(func,filter(list,predicate))代替,或者被一些语句代替,比如perl:for (0..9) { if ( ($_ % 2) == 0) {push @result, $_*2 }}.
  • 这种存在于多种语言中的特殊语法,其实不是必要的。如果需要这样的函数,那么它可以直接是一个一般的函数,比如LC(function,list,predicate).

列表解析语法并不是很有必要。一个更好更一致的方法是用函数式语言的精髓,使用普通函数的组合。

这是python的语法
:

在Mathematica中,可以这样写

在Mathematica中,算术操作符可以不使用Map而直接映射到列表,因此上面的代码可以这样写:

还可以写成线性前缀风格:

或者线性后缀风格:

在上面,我们就像Unix里的管道那样排列函数在一起。我们从9开始,使用“Range”来获取一个1到9的列表,然后使用一个函数来过滤出偶数,接着我们使用一个函数来把过滤出来的每个数字乘以2。符号“//”是一个后缀符号,类似于bash(shell)的“|”符号,同时,“@”是一个与“|”相反的符号。

(☛ Short Intro of Mathematica For Lisp Programers)

无需特殊语法的列表理解函数

在函数式语言中,假如我们想要“列表解析”这一特性。通常地,默认情况这可以这样做

但这种用法会很频繁,我们想为此创建一个更方便的函数。作为一个独立的函数,它更容易被编译器优化。因此,我们可以创建一个函数LC像这样:

这个关系到一种语言是否应该创建一个更方便的新函数,否则就需要3个函数的组合。Common Lisp和Scheme Lisp是极端对立的典型例子。

注意,这里没涉及到新的语法。

假设,某人对下面的有争论:

实际上, 这个语法:

远比这个语法方便: