具有rest参数的函数调用具有rest参数的函数 [英] Function with rest arguments calling a function with rest arguments
问题描述
让我们假设我们有一个函数 func1
:
Let us suppose we have a function func1
:
(defun func1 (&rest values)
; (do something with values...)
(loop for i in values collect i))
现在,我们有一个函数 func2
调用了 func1
:
Now, we have a function func2
which calls func1
:
(defun func2 (&rest values)
; (do something with values...)
(func1 ???))
我应该放什么而不是 ???
将 func2
的值
的所有参数复制到 func1
的值
?
What should I put instead of ???
to "copy" all the parameters of func2
's values
to func1
's values
?
例如,我将具有以下行为:
For instance, I would have the following behavior :
(func2 1 2 3 4) ; result is (1 2 3 4) and not ((1 2 3 4)).
在一个更早的问题我试图做这样的事情:
In an earlier question I tried to do something like this :
(defun func2 (&rest values)
(macrolet ((my-macro (v)
`(list ,@v)))
(func1 (my-macro values))))
但是defun无法获得值,因为它不是运行时。在此答案中,他建议我使用 apply
,但这函数也需要& rest
参数,所以它不能解决我的问题...
But the defun cannot get the value because it is not runtime. In this answer, he suggested that I use apply
, but this function takes a &rest
parameter too, so it doesn't solve my problem...
,我宁愿避免更改这两个函数的原型以及 func1
的行为。
If possible, I would rather avoid to change the prototype of both functions, and the behavior of func1
.
推荐答案
在常见的Lisp中,必须是
In common lisp, it has to be
(apply #'func1 values) ;; since `func1` has to be looked up in function namespace
中查找`func1`,所以Clojure和Racket / Scheme是Lisp1 ,而常见的lisp是Lisp2。
remember, Clojure and Racket/Scheme are Lisp1, and common lisp is Lisp2.
替代解决方案(仅为了方便)
我在问自己,如何在没有申请
的情况下完成它-只是为了方便。
问题
I was asking myself, how to get it done without apply
- just for the sake.
The problem with
`(func2 ,@values)
是,例如,
(func2 (list 1 2 3) (list 4) 5)
称为值
变量是((1 2 3)(4)5)
但是当它被拼接成( func1,@ values)
,创建的是
(func1(1 2 3)(4)5)
。但是,如果将其与 func2
调用进行比较,则
应该是(func1(列表1 2 3)(列表4)5 )
这可能是不可能的,因为调用(func2(列表1 2 3)(列表4)5)
时-
以简洁的方式-在进入 func2
的函数主体之前,分别评估 func2
的参数,因此我们最终以值
作为已求值参数的列表,即(((1 2 3)(4)5)
is called, the values
variable is ((1 2 3) (4) 5)
But when it is spliced into (func1 ,@values)
, what is created is
(func1 (1 2 3) (4) 5)
. But if we compare this with the func2
call,
it should be rather (func1 (list 1 2 3) (list 4) 5)
which is perhaps not possible, because when (func2 (list 1 2 3) (list 4) 5)
is called -
in the lisp manner - the arguments of func2
are each evaluated, before they enter the function body of func2
, so we end up with values
as a list of already evaluated arguments, namely ((1 2 3) (4) 5)
.
因此,在最后一个表达式中,关于 func1
的参数,我们是一种评估-步骤。
So somehow, concerning the arguments for func1
in the last expression, we are one evaluation-step offbeat.
但是有一种使用 quote 的解决方案,我们设法在引用每个参数之前将其引给在最后一个表达式中的 func1
,以同步 func1
函数调用-该参数的评估会暂停一轮。
But there is a solution with quote, that we manage to quote each of the arguments before giving it to func1
in the last expression, to "synchronize" the func1
function call - to let the arguments' evaluation pause for one round.
所以我的首要目标是生成一个 func2
主体内的新 values
列表,其中引用了每个值列表的参数(在let-捆绑)。
然后最后将这个引用值
列表拼接到最后一个表达式中:(func1'(1 2 3)'( 4)'5)
,对于这种情况,它可以等同于(func1(列表1 2 3)(列表4)5)
问题/此类呼叫。
这是通过以下代码实现的:
So my first aim was to generate a new values
list inside the func2
body where each of the values list's argument is quoted (this is done in the let-binding).
And then at the end to splice this quoted-values
list into the last expression: (func1 '(1 2 3) '(4) '5)
which can be regarded as equivalent to (func1 (list 1 2 3) (list 4) 5)
for this kind of problems / for this kind of calls.
This was achieved by this code:
(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))))
这是一种宏(它创建代码btw。它组织新的代码),但在运行时执行和创建-而不是在预编译时创建。使用 eval
我们可以即时执行生成的代码。
This is kind of a macro (it creates code btw. it organizes new code) but executed and created in run-time - not in pre-compile time. Using an eval
we execute that generated code on the fly.
与 macroexpand- 1
,我们可以通过删除 eval来查看
-我称之为 func1
表达式展开的结果-代码- func2-1
:
And like macroexpand-1
, we can look at the result - the code - to which the func1
expression "expands", by removing eval
around it - I call it 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
版本中将其消失之前立即返回最后一个表达式作为代码:
And if we run it, it returns the last expression as code immediately before it is evluated in the func2
version:
(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
进行了评估:
And this happens if we call it using func2
(so with evaluation of the func1
all:
(func2 (list 1 2 3) (list 4) 5)
;; ((1 2 3) (4) 5) ;; the result of (FUNC1 '(1 2 3) '(4) '5)
所以我想这正是您想要的!
So I would say this is exactly what you desired!
这篇关于具有rest参数的函数调用具有rest参数的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!