在Scheme中,函数
(map fn list0 [list1 .. listN])
有一个限制,即列表必须具有相同数量的元素。来自Python,我错过了Python列表推导式的自由,它看起来很像上面的map
,但没有这个限制。
我很想实现一个替代的“my-map”,它允许不同大小的列表,迭代所有列表的前 N 个元素,其中 N 是最短列表的长度。
例如,令
num
为 10
,lst
为 (1 2 3)
。对于 my-map,我希望写出这样的表达式:
(my-map + (circular-list num) lst)))
并得到:
(11 12 13)
我比传统的阅读方式更容易阅读这篇文章
(map + (lambda (arg) (+ num arg)) lst)
或
(map + (make-list (length lst) num) lst)
两个问题:
首先,请注意
map
允许空列表,但当然,如果有一个空列表,那么所有列表都应该为空。
其次,看一下map
此过程从 R5RS 规范扩展而来,允许参数长度不等;当最短列表用完时它终止。
第三,大多数Scheme程序员都非常喜欢
(map (lambda (arg) (+ num arg)) lst)
我的猜测是,Scheme 与 Python 的不同之处在于,当您习惯该语言时,
lambda
表达式变得越来越可读。
最后,有一些实现带有某种形式的列表理解。 例如,在Racket中你可以写:
(for/list ([arg lst]) (+ num arg))
您提到查看 SRFI-42,但表示如何像 Python 列表理解一样使用它并不明显。所以,一个演示(使用Gauche,但它得到一些流行的方案实现的支持):
gosh$ (import (scheme base) (srfi 42))
gosh[r7rs.user]$ (define num 10)
num
gosh[r7rs.user]$ (define lst '(1 2 3))
lst
gosh[r7rs.user]$ (list-ec (: i lst) (+ i num))
(11 12 13)
如果你想一次迭代多个列表,在最短的地方停止,就像评论中的Python示例
[f(x, y) for x, y in zip(x_list, y_list)]
,它看起来像:
(list-ec (:parallel (: x x-list) (: y y-list)) (f x y))