Common Lisp:在不使用 &rest 参数的情况下高效地处理提供的 p 参数

Common Lisp: Efficiently handling supplied-p-parameter efficiently without using &rest arguments

假设我有函数

(defun bar (a &optional (b nil bp))
  (declare (ignore a b bp)) ; <-- replace it with (list a b bp)
                            ;     to check for correctness
  )
;; I want to preserve the value of bp here inside bar, and inside foo below

我想围绕 bar 写一个包装器:

(defun foo (a &optional (b nil bp))
  (declare (optimize speed))
  (apply #'bar a (nconc (when bp (list b)))))

同时在从 foobar 的调用中保留 bp 的值,并使参数 b 在 emacs 的迷你缓冲区/eldoc 中可见模式。我想知道在这个调用中是否有一种可能不可移植的非强制性方法来保留 bp 的值。

例如,

CL-USER> (time (loop repeat 1000000 do (foo 4 2)))
Evaluation took:
  0.040 seconds of real time
  0.043656 seconds of total run time (0.043656 user, 0.000000 system)
  110.00% CPU
  96,380,086 processor cycles
  15,990,784 bytes consed <--- plenty of consing
  
NIL

如果我忽略 b-visibility-in-eldoc,我可能会使用 &rest 参数,但我确实希望参数可见。

虽然在这种特殊情况下还有其他方法可以实现这一点,但我确实想考虑存在多个 &optional(或 &keyword)参数的情况。

我不确定 barfoo 实际上应该做什么,但是:

(defun foo (a &optional (b nil bp))
  (declare (optimize speed))
  (funcall #'bar a (when bp b))) 

CL-USER> (time (loop repeat 1000000 do (foo 4 2)))
Evaluation took:
  0.005 seconds of real time
  0.005810 seconds of total run time (0.005804 user, 0.000006 system)
  120.00% CPU
  8,099,624 processor cycles
  0 bytes consed

使用 cond 表格来决定如何调用 bar:

(defun bar (a &optional (b nil bp) (c nil cp))
  (declare (ignore a b bp c cp)))

(defun foo (a &optional (b nil bp) (c nil cp))
  (declare (optimize speed))
  (cond (cp (funcall #'bar a b c))
        (bp (funcall #'bar a b))
        (t (funcall #'bar a))))
CL-USER> (time (loop repeat 1000000 do (foo 1 2 3)))
Evaluation took:
  0.015 seconds of real time
  0.017203 seconds of total run time (0.017148 user, 0.000055 system)
  113.33% CPU
  41,186,554 processor cycles
  0 bytes consed

检查传递给 bar 的参数:

(defun bar (a &optional (b nil bp) (c nil cp))
  (list a b bp c cp))
CL-USER> (foo 1 2 3)
(1 2 T 3 T)
CL-USER> (foo 1 2)
(1 2 T NIL NIL)
CL-USER> (foo 1)
(1 NIL NIL NIL NIL)