在 Common Lisp 中,它必须是
(apply #'func1 values) ;; since `func1` has to be looked up in function namespace
请记住,Clojure 和 Racket/Scheme 是 Lisp1,而 common lisp 是 Lisp2。
替代解决方案(只是为了方便)
我问自己,如何在没有apply
-只是为了。
问题在于
`(func2 ,@values)
是,如果例如
(func2 (list 1 2 3) (list 4) 5)
被称为,values
变量是((1 2 3) (4) 5)
但当它被拼接成(func1 ,@values)
,创建的是(func1 (1 2 3) (4) 5)
。但如果我们将其与func2
称呼,
应该是(func1 (list 1 2 3) (list 4) 5)
这也许是不可能的,因为当(func2 (list 1 2 3) (list 4) 5)
叫做 -
以 lisp 方式 - 的论点func2
在进入函数体之前分别进行评估func2
,所以我们最终得到values
作为已评估参数的列表,即((1 2 3) (4) 5)
.
所以不知何故,关于论点func1
在最后一个表达式中,我们是一步评估另类.
但有一个解决方案quote,我们在给出每个参数之前设法引用它func1
在最后一个表达式中,“同步” the func1
函数调用 - 让参数的计算暂停一轮。
所以我的首要目标是产生一个新的values
列出里面的func2
body,其中每个值列表的参数都被引用(这是在 let 绑定中完成的)。
然后在最后拼接这个quoted-values
列出最后一个表达式:(func1 '(1 2 3) '(4) '5)
可以看作等价于(func1 (list 1 2 3) (list 4) 5)
对于此类问题/此类调用。
这是通过以下代码实现的:
(defun func2 (&rest vals)
(let ((quoted-values (loop for x in vals
collect `',x)))
; do sth with vals here - the func2 function -
(eval `(func1 ,@quoted-values))))
这是一种宏(顺便说一句,它创建代码。它组织新代码),但在运行时执行和创建 - 而不是在预编译时。使用eval
我们即时执行生成的代码。
并且喜欢macroexpand-1
,我们可以查看结果 - 代码 -func1
表达式“扩展”,通过删除eval
围绕着它——我称之为func2-1
:
(defun func2-1 (&rest vals)
(let ((quoted-values (loop for x in vals
collect `',x)))
; do sth with vals here - the func2 function -
`(func1 ,@quoted-values)))
如果我们运行它,它会立即将最后一个表达式作为代码返回,然后再在func2
版本:
(func2-1 (list 1 2 3) (list 4) 5)
;; (FUNC1 '(1 2 3) '(4) '5) ;; the returned code
;; the quoted arguments - like desired!
如果我们使用它来调用它,就会发生这种情况func2
(因此评估func1
all:
(func2 (list 1 2 3) (list 4) 5)
;; ((1 2 3) (4) 5) ;; the result of (FUNC1 '(1 2 3) '(4) '5)
所以我想说这正是您想要的!