第一个问题:假设 Common Lisp 的现代编译器通常会将 (mapcar #'fn ...)
和 (map 'list #'fn ...)
编译成与 (mapc #'fn ...)
相同的代码是否合理?也就是说,假设编译器会看到返回值被忽略,因此不需要构造新列表是否合理?例如假设我的源文件包含以下代码:
(defun set-foo-5 (sym)
(setf (get sym 'foo) 5))
(progn
(mapcar #'set-foo-5 '(a b c))
(format t "All foos are five!~%"))
mapc
会更有效吗?我通常运行 SBCL,但我的猜测是任何好的编译器都能够弄清楚在这种情况下没有必要创建一个新列表。我对吗?第二个问题:在相同的情况下,我是否应该假设现代编译器通常会将
map 'list
编译为与 mapcar
相同的代码,只要源代码中存在 'list
并且在运行时未选择?第三个问题:其他序列的类似问题。例如,如果我用
mapcar
替换上面 progn 中的 (map 'vector #'set-foo-5 #(a b c))
行,我是否应该假设编译后的代码不会费心构造一个新的向量?
最佳答案
首先是 , map
和 mapcar
有一个非常重要的区别:后者作用于 lists 而前者作用于任何 sequences 。这意味着只有当编译器可以证明所有数据参数都是 (map nil ...)
时,(map 'list ...)
(或 (mapc ...)
)才等价于 (mapcar ...)
(resp. list
)。
其次 ,大多数现代 Lisp 编译器(例如 SBCL )通常足以解决这些问题(必要时带有声明)。
第三个 ,唯一可以确定的方法是使用 disassemble
。
第四个 ,函数选择是一种记录代码的方式。当您使用 map
时,您是在告诉代码的人类读者您将向函数传递非列表。如果您确定只使用列表,您为什么要混淆读者(几个月后的您自己)?
第五个 , premature optimization is the root of all evil 。
关于common-lisp - 忽略结果时,MAPCAR、MAPC 和 MAP 是否编译为类似的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19071338/