第一个问题:假设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!~%"))
Run Code Online (Sandbox Code Playgroud)
会mapc更高效吗?我经常运行SBCL,但我的猜测是任何好的编译器都能够发现在这种情况下不需要占用新的列表.我对吗?
第二个问题:在同样的情况下,我是否应该假设现代编译器通常编译map 'list成相同的代码mapcar,只要'list在源代码中存在,而不是在运行时选择?
第三个问题:其他序列的类似问题.例如,如果我替换mapcar上面的预测中的行(map 'vector #'set-foo-5 #(a b c)),我应该假设编译的代码不会费心构造新的向量吗?
sds*_*sds 10
首先,map并且mapcar在一个非常重要的方面有所不同:后者在列表上运行,而前者在任何序列上运行.这意味着只有当编译器能够证明所有数据参数都是s时,(map nil ...)(或(map 'list ...))等效于(mapc ...)(resp.(mapcar ...)).list
其次,大多数现代Lisp编译器(例如,SBCL)通常都足以弄清楚这些事情(必要时使用声明).
第三,唯一可以确定的方法是使用disassemble.
第四,函数选择是一种记录代码的方法.当您使用时map,您告诉人类读者您的代码将要将非列表传递给该函数.如果您确定只使用列表,为什么要混淆读者(几个月后你自己)?
第五,过早优化是万恶之源.