计算机语言设计:列表的理解以及为什么它是有害的
admin
2023-07-31 00:38:55
0

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

何为列表解析?

以python中的列表解析为例:

1 S = [2*n for n in range(0,9) if ( (n % 2) == 0)] print S # prints [0, 4, 8, 12, 16]

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

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

1 [myExpression for myVar in myList if myPredicateExpression]

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

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

 

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

1 map( f, filter(list, predicate))

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

Haskell

1 s = [ 2*x | x < [0..], x^2 > 3 ]

F#

1 seq { for x in 0..100 do if x*x > 3 then yield 2*x } ;;

OCaml

1 [? 2 * x | x < 0 max_int ; x * x > 3 ?];;

Clojure

1 (take 20 (for [x (iterate inc 0) :when (> (* x x) 3)] (* 2 x)))

Common Lisp

1 (loop for x from 1 to 20 when (> (* x x) 3) collect (* 2 x))

Erlang

1 S = [2*X || X < lists:seq(0,100), X*X > 3].

Scala

1 val s = for (x < Stream.from(0); if x*x > 3) yield 2*x

这里是维基百科对
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).

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

1 map( f, filter(list, predicate))

这是python的语法
:

1 map(lambda x: 2*x , filter( lambda x:x%2==0, range(9) ) ) # result is [0, 4, 8, 12, 16]

在Mathematica中,可以这样写

1 Map[ #*2

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

1 Select[Range@9, EvenQ] * 2

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

1 (#*2

或者线性后缀风格:

1 9 // Range  // (Select[#, EvenQ]

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

(☛ Short Intro of Mathematica For Lisp Programers)

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

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

1 map(func, filter(inputList, Predicate))

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

1 LC(func, inputList, Predicate)

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

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

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

实际上, 这个语法:

1 [x+1 for x in [1,2,3,4,5] if x%2==0]

远比这个语法方便:

1

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...