创建可以将 lambda 应用于上下文中的列表的 Lisp 宏

The*_*rse 2 lisp macros lambda clisp common-lisp

基本上我正在尝试编写一个 Common Lisp 宏,定义为:

(defmacro applyfunct (function arguments variables))
Run Code Online (Sandbox Code Playgroud)

将作为参数给出的函数应用function到参数arguments(这是一个应用函数的参数列表),在必要时,使用列表列表中给定的变量variables。因此,使用这些参数调用时的返回值如下:

(applyfunct + (7 5) ((x 1) (y 2)))
Run Code Online (Sandbox Code Playgroud)

将是 12,考虑到 7+5=12,并且不需要上下文变量 x 和 y 将函数应用于参数。但是,当它确实需要给定的上下文变量时:

(applyfunct (lambda (x y) (+ (* a x) (* y b)) (4 2) ((a 2) (b 4))))
Run Code Online (Sandbox Code Playgroud)

如果在为求值返回 16 的函数中需要这些变量,它应该使用这些变量,因为:

(applyfunct (lambda (x y) (+ (* a x) (* y b)) (4 2) ((a 8) (b 1))))
;                    4 2        8 4     2 1    
; (+ (* 8 4) (* 2 1)) => 34
Run Code Online (Sandbox Code Playgroud)

希望我在这里的评论可以清楚地说明我正在尝试做什么。到目前为止我所拥有的是:

(defmacro applyfunct (function arguments variables)
    (let ( ((car (first contents)) (cdar (first contents))
           ((car (second contents)) (cdar (second contents))
Run Code Online (Sandbox Code Playgroud)

但我不知道如何继续......

(apply function arguments) 
Run Code Online (Sandbox Code Playgroud)

仅适用于函数为 + 的第一个示例调用,而不适用于使用 lambda 的第二个函数调用。我在这里错过了什么吗?我应该以某种方式使用 ` 或 #' 吗?注意:我正在尝试尽可能按功能进行编程(最小到没有副作用,例如,不使用 setq)。我也在使用 Common Lisp 的 CLISP 实现。

mel*_*ene 5

据我所知,apply仅适用于第二个示例 ( lambda),而不适用于+.

但请记住,您正在编写一个宏,它可以根据需要构造程序代码(例如(+ 7 5)((lambda (x y) ...) 4 2))。

第一步是使函数调用起作用(暂时忽略variables)。在 Lisp 中,函数调用的句法形式是一个列表,它的第一个元素(头)是函数,其余元素(尾)是函数参数。可以使用以下方法构建此结构cons

(defmacro applyfunct (function arguments variables)
    (cons function arguments))
Run Code Online (Sandbox Code Playgroud)

或者,使用以下语法糖`

(defmacro applyfunct (function arguments variables)
    `(,function ,@arguments))
Run Code Online (Sandbox Code Playgroud)

`就像一个代码模板,,标记要插入变量的位置,并,@另外展平列表。)

现在,为了variables工作,let可用于提供绑定(如在您的代码中)。但是,不需要variables手动解构;它已经具有let绑定列表的正确形状:

(defmacro applyfunct (function arguments variables)
    `(let ,variables
        (,function ,@arguments)))
Run Code Online (Sandbox Code Playgroud)

我们可以测试这个宏:

(print (macroexpand-1 '(applyfunct (lambda (x y) (+ (* a x) (* y b))) (4 2) ((a 8) (b 1)))))
; by the way, one of the ') is misplaced in your example: ----------^
Run Code Online (Sandbox Code Playgroud)

产生这个输出:

(LET ((A 8) (B 1)) ((LAMBDA (X Y) (+ (* A X) (* Y B))) 4 2))
Run Code Online (Sandbox Code Playgroud)

......这正是我们想要的。