Common Lisp 中的递归宏

Recursive macro in Common Lisp

我必须在 Common Lisp 中编写递归宏。

我有一个搜索列表中最大元素的函数。例如它 returns 45 列表 (2 4 6 42 5 45 3)。现在我要把它转换成递归宏。

这是我的代码:

(defmacro mymax (values)                     
    (cond 
        ((= (length values) 1) `(write (car ,values)))
        ((> (car values) (cadr values)) (mymax (list (car values) (cddr values))))    
        (t (mymax (cdr values)))
    )
)       

没用。编译错误:"LIST is not a real number"。我尝试了 '`' 和 ',' 的不同组合 - 但没有结果。如何更正我的代码以使宏的结果为数字?

宏调用: (write (mymax (list 3 5 6 7 8)))

(write (mymax (cons 3 5 6 7 8)))

(write (mymax '(3 5 6 7 8)))

所有这些调用都以相同的结果结束。

(a b c)

  • 如果您阅读上面的表格,它是一个包含 3 个符号的列表。
  • 当你评估它时,如果a没有绑定到宏,那么形式是对a[=45的函数调用=] 其中 bc 被评估。

'(a b c)、a.k.a。 (quote (a b c))

  • 如果你阅读这个,你有一个包含两个元素的列表,第一个是quote,然后是一个包含3个符号的列表。
  • 如果您评估 表单,返回值是一个包含 3 个符号的列表:(a b c)

Lisp reader.

read 给出了宏未评估的源代码

(mymax '(1 2 3))中,'(1 2 3)是未计算的形式(quote (1 2 3))。在 (mymax (list 1 2 3)) 中,未计算的参数有 4 个元素,第一个是符号。您应该为宏提供什么,以便它具有以下列表 (1 2 3)?

如有疑问,宏展开。

这是函数 MAX 的宏版本,当每个参数都是数字时它会做一些有用的事情:

(defmacro mymax (&rest numbers)
  (flet ((all-number-list-p (list)                     ; local function
           (and (listp list)                           ; it's a list
                (numberp (first list))                 ; the first number exists
                (every #'numberp list))))              ; everything is a number
    (if (all-number-list-p numbers)                    ; only numbers? 
        (cond ((null (rest numbers)) (first numbers))  ; one number
              ((> (first numbers) (second numbers))    : first is greater
               `(mymax ,@(cons (first numbers)         ; get rid of the second
                               (cddr numbers))))
              (t                                       ; second is greater
               `(mymax ,@(rest numbers))))             ; get rid of the first
      `(max ,@numbers))))                              ; fallback, use MAX

示例:

CL-USER 23 > (macroexpand-1 '(mymax 4 1 3 2))
(MYMAX 4 3 2)
T

CL-USER 24 > (macroexpand-1 '(mymax 4 3 2))
(MYMAX 4 2)
T

CL-USER 25 > (macroexpand-1 '(mymax 4 2))
(MYMAX 4)
T

CL-USER 26 > (macroexpand-1 '(mymax 4))
4
T

CL-USER 27 > (mymax 4 1 3 2)
4

请注意,当并非每个参数都是数字时,它只使用 MAX

CL-USER 28 > (macroexpand-1 '(mymax a b 8 d))
(MAX A B 8 D)