首先,请原谅我用这么一个又长又混乱又不知所云的标题。因为这个问题实在是过于诡异,我无法用简单的标题进行描述。还是看下面的代码吧
(setq lexical-binding t)
;; From dash.el
(defmacro --filter (form list)
"Anaphoric form of `-filter'.
See also: `--remove'."
(declare (debug (form form)))
(let ((r (make-symbol "result")))
`(let (,r)
(--each ,list (when ,form (!cons it ,r)))
(nreverse ,r))))
(defun -filter (pred list)
"Return a new list of the items in LIST for which PRED returns a non-nil value.
Alias: `-select'
See also: `-keep', `-remove'."
(--filter (funcall pred it) list))
dash里面有这么两个函数,功能和cl-remove-if-not
是一样的。
然后我自己实现了这么一个函数
(defmacro my--filter (form list)
(let ((elem (make-symbol "elem")))
`(apply #'nconc (mapcar (lambda (,elem)
(and (funcall (lambda (it) ,form) ,elem)
(list ,elem))) ,list))))
(defun my-filter (fn list)
(my--filter (funcall fn it) list))
功能大致上和--filter
是一样的,至少输入参数是列表时行为和--filter
一致
接下来有趣的事情要发生了
(-dotimes 10
(lambda (x)
(benchmark 1000 '(-filter #'cl-evenp '(3 4 5 6 7)))
(benchmark 1000 '(my-filter #'cl-evenp '(3 4 5 6 7)))
(message "\n")))
Elapsed time: 0.001790s
Elapsed time: 0.002837s
[2 times]
Elapsed time: 0.000748s
Elapsed time: 0.003137s
[2 times]
Elapsed time: 0.000803s
Elapsed time: 0.003746s
[2 times]
Elapsed time: 0.000755s
Elapsed time: 0.003723s
[2 times]
Elapsed time: 0.000753s
Elapsed time: 0.003730s
[2 times]
Elapsed time: 0.000766s
Elapsed time: 0.003868s
[2 times]
Elapsed time: 0.000758s
Elapsed time: 0.003937s
[2 times]
Elapsed time: 0.000836s
Elapsed time: 0.003930s
[2 times]
Elapsed time: 0.000756s
Elapsed time: 0.003832s
[2 times]
Elapsed time: 0.000701s
Elapsed time: 0.003863s
(-dotimes 10
(lambda (x)
(benchmark 1000 '(--filter (cl-evenp it) '(3 4 5 6 7)))
(benchmark 1000 '(my--filter (cl-evenp it) '(3 4 5 6 7)))
(message "\n")))
Elapsed time: 0.006269s
Elapsed time: 0.003397s
[2 times]
Elapsed time: 0.006261s
Elapsed time: 0.003413s
[2 times]
Elapsed time: 0.005818s
Elapsed time: 0.049709s (0.045985s in 1 GCs)
[2 times]
Elapsed time: 0.005700s
Elapsed time: 0.003090s
[2 times]
Elapsed time: 0.005880s
Elapsed time: 0.003282s
[2 times]
Elapsed time: 0.006212s
Elapsed time: 0.003704s
[2 times]
Elapsed time: 0.006333s
Elapsed time: 0.003446s
[2 times]
Elapsed time: 0.006209s
Elapsed time: 0.003425s
[2 times]
Elapsed time: 0.005760s
Elapsed time: 0.003607s
[2 times]
Elapsed time: 0.005901s
Elapsed time: 0.003197s
[3 times]
[2 times]
emmm,我自己实现的macro比原装macro快了2倍,但是函数版本比原装函数慢了2倍?不科学啊!
我不是很懂elisp interpreter的内部实现。所以有点好奇,导致宏和函数性能差异巨大的原因究竟是什么?