Common lisp 用于展开作为rest传递的参数列表的公共Lisp宏,如:(foo(展开栏100 200 300))=>;(foo(第100条)(第200条)(第300条))

Common lisp 用于展开作为rest传递的参数列表的公共Lisp宏,如:(foo(展开栏100 200 300))=>;(foo(第100条)(第200条)(第300条)),common-lisp,defmacro,Common Lisp,Defmacro,很抱歉这个标题很笨拙,但我很难用几句话来描述我要找的东西 我正在从事一个常见的Lisp DSL项目,我想知道是否有以下可能: DSL可能有几个功能 (defun foo(&rest)) 及 (除霜条(arg)) 将按以下方式使用: (foo(bar 100)(bar 200)(bar 300)(bar 400)(bar 500))等 现在,这是很多冗余的输入,所以我想知道是否有可能创建一个扩展宏 那将考虑到 (foo(扩展条100 200 300 400 500)) 不改变foo本身 不需要宏:

很抱歉这个标题很笨拙,但我很难用几句话来描述我要找的东西

我正在从事一个常见的Lisp DSL项目,我想知道是否有以下可能:

DSL可能有几个功能

(defun foo(&rest))

(除霜条(arg))

将按以下方式使用:

(foo(bar 100)(bar 200)(bar 300)(bar 400)(bar 500))等

现在,这是很多冗余的输入,所以我想知道是否有可能创建一个扩展宏 那将考虑到

(foo(扩展条100 200 300 400 500))


不改变foo本身

不需要宏:

(defun foo (&rest rest)
  (apply #'+ rest)) ; for example add all together 

(defun bar (arg)
  (1+ arg)) ; 1+ is only an example here

(apply #'foo (mapcar #'bar '(100 200 300 400 500)))

不需要宏:

(defun foo (&rest rest)
  (apply #'+ rest)) ; for example add all together 

(defun bar (arg)
  (1+ arg)) ; 1+ is only an example here

(apply #'foo (mapcar #'bar '(100 200 300 400 500)))

不,如果不改变你正在定义的函数的特征(或者可能使用一些毛茸茸的东西重新定义宏扩展),就无法做到这一点:你有我所说的“扩展/无扩展阻抗失配”,这不能用CL中的标准宏来解决

“nospread”函数是将其所有参数包装成一个形式的函数。“spread”函数每个参数有一个形式参数。我在使用INTERISP时学会了这些术语:它们可能早于INTERISP,但它们现在似乎大多未被使用。CL函数只能部分展开(
(foo-bar&rest-more)
)。您的
foo
未发布

扩展/无扩展阻抗不匹配是指当您有扩展功能但需要无扩展功能时,或者反之亦然。这几乎总是一个设计问题的标志。扩散/无扩散问题的解决方法通常涉及
apply

您的问题是
foo
是一个nospread函数:它将其所有参数转换为一个列表,但您希望宏将其视为一个扩展函数,为其提供一个参数列表

特别是,在CL中,对于任何
y
、函数或宏(见下文),像
(x(y…)
这样的表达式永远不能转换为
(x a1 a2…

在你的情况下,你想要

(foo (expand bar a b ...)
变成

(foo (bar a) (bar b)
这是不可能的


有一些Lisp被称为“拼接宏”,其中宏的扩展可以“拼接”到列表中,就像
,@
对反引号所做的那样。可能是CL有拼接宏包,甚至可能是可移植的:使用
*macroexpand hook*
可以走很长的路。但是标准CL宏无法做到这一点。

不,如果不更改您正在定义的函数的签名(或者可能使用一些毛茸茸的东西重新定义宏扩展),就无法做到这一点:我称之为“扩展/无扩展阻抗失配”,这无法用CL中的标准宏解决

“nospread”函数是将其所有参数包装成一个形式的函数。“spread”函数每个参数有一个形式参数。我在使用INTERISP时学会了这些术语:它们可能早于INTERISP,但它们现在似乎大多未被使用。CL函数只能部分展开(
(foo-bar&rest-more)
)。您的
foo
未发布

扩展/无扩展阻抗不匹配是指当您有扩展功能但需要无扩展功能时,或者反之亦然。这几乎总是一个设计问题的标志。扩散/无扩散问题的解决方法通常涉及
apply

您的问题是
foo
是一个nospread函数:它将其所有参数转换为一个列表,但您希望宏将其视为一个扩展函数,为其提供一个参数列表

特别是,在CL中,对于任何
y
、函数或宏(见下文),像
(x(y…)
这样的表达式永远不能转换为
(x a1 a2…

在你的情况下,你想要

(foo (expand bar a b ...)
变成

(foo (bar a) (bar b)
这是不可能的


有一些Lisp被称为“拼接宏”,其中宏的扩展可以“拼接”到列表中,就像
,@
对反引号所做的那样。可能是CL有拼接宏包,甚至可能是可移植的:使用
*macroexpand hook*
可以走很长的路。但是标准CL宏无法做到这一点。

将dsl分为两部分可能是值得的,一部分是您编程时使用的更简单的版本,另一部分是用户友好的版本。例如:

(in-package #:impl)
(defun foo (&rest args) ...)
(defun bar (arg) ...)

(in-package #:dsl)
(defun foo (&rest args) (apply #'impl:foo (append args)))
(defun bar (&rest args) (mapcar #'impl:bar args))
(foo (bar 100 200 300 400 500))

将您的dsl分为两个部分可能是值得的,一个是您编程时使用的更简单的版本,另一个是用户友好的版本。例如:

(in-package #:impl)
(defun foo (&rest args) ...)
(defun bar (arg) ...)

(in-package #:dsl)
(defun foo (&rest args) (apply #'impl:foo (append args)))
(defun bar (&rest args) (mapcar #'impl:bar args))
(foo (bar 100 200 300 400 500))

嗯,使用
apply
始终是一个选项,尽管我想知道如果没有它是否可能。在这种情况下,我想如果你可以使用相同的功能(DSL针对的是那些本身并不真正了解CL的人)“嗯,是的,使用apply总是一个选项”--不总是,只针对函数,不针对宏;-)嗯,使用
apply
始终是一个选项,尽管我想知道如果没有它是否可能。在这种情况下,我想如果你可以使用相同的功能(DSL针对的是那些本身并不真正了解CL的人)“嗯,是的,使用apply总是一个选项”--不总是,只针对函数,不针对宏;-)谢谢你的详细回答,也谢谢你的术语更新。话虽如此,但在寻找包裹时发现了两个似乎与您描述的完全一样的东西:@EllipsenPark:是的,我隐约意识到了这一点。据我所知,它使用
*macroexpandhook*
来完成它的工作。CL没有更多这样的钩子变量,这让我有点恼火,因为它们非常灵活