具有rest参数的函数调用具有rest参数的函数 [英] Function with rest arguments calling a function with rest arguments

查看:126
本文介绍了具有rest参数的函数调用具有rest参数的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们假设我们有一个函数 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆