0

对不起,笨拙的标题,但我很难用几句话来描述我正在寻找的东西......

我正在开发一个 Common Lisp DSL 项目,我想知道以下是否可行:

DSL 可能有几个功能

(defun foo (&rest rest))

(defun bar (arg))

将按以下方式使用:

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

现在,这是很多多余的输入,所以我想知道是否可以创建一个扩展宏来允许

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

不改变foo自己?

4

3 回答 3

1

不需要宏:

(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)))
于 2020-04-19T18:13:47.103 回答
1

不,如果不更改您正在定义的函数的签名(或可能使用一些重新定义宏扩展的毛茸茸的东西),这是无法完成的:您有我所说的“扩展/非扩展阻抗不匹配”,无法解决CL 中的标准宏。

“nospread”函数是将所有参数包装成一个形式的函数。“扩展”函数的每个参数都有一个形式。我在使用 InterLisp 时了解了这些术语:它们可能早于它,但现在它们似乎大多未使用。CL 函数只能部分不扩展 ( (foo bar &rest more))。你foo的没有传播。

扩展/未扩展阻抗不匹配是指您具有扩展函数但想要一个未扩展函数,反之亦然。这几乎总是一个设计问题的迹象。spread/nospread 问题的解决方法通常涉及apply.

您的问题是它foo是一个 nospread 函数:它将所有参数转换为一个列表,但您希望宏将其视为扩展函数,并将其传递给单个参数列表。

特别是,在 CL 中,对于任何、函数或宏(但请参见下文),(x (y ...))永远不会变成like 的表达式,这就是您需要发生的事情。(x a1 a2 ...)y

在你的情况下,你想要类似的东西

(foo (expand bar a b ...)

变成

(foo (bar a) (bar b)

这不可能发生。

Lisps 有一些被称为“拼接宏”的东西,其中宏的扩展可以“拼接”到一个列表中,就像,@反引号一样。可能是有 CL 的拼接宏包,甚至可能是它们是可移植的:你可以用*macroexpand-hook*. 但是标准的 CL 宏不能做到这一点。

于 2020-04-20T10:01:27.633 回答
0

将您的 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))
于 2020-04-20T22:14:56.693 回答