Common Lisp中的递归宏

时间:2015-10-15 22:40:00

标签: recursion macros lisp common-lisp

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

我有一个搜索列表中最大元素的函数。例如,它返回 列表45的{​​{1}}。现在我要将它转换为递归宏。

这是我的代码:

(2 4 6 42 5 45 3)

它不起作用。编译错误:" LIST不是实数"。我尝试过不同的“'`'和',' - 没有结果。如何更正我的代码,以便宏的结果是一个数字?

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

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

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

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

2 个答案:

答案 0 :(得分:2)

(a b c)

  • 如果您在上面的表单中阅读,则会列出3个符号。
  • 当您评估时,如果a未绑定到宏,则表单是对 a 的函数调用,其中 b <评估/ em>和 c

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

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

Lisp阅读器为宏提供了未评估的源代码 read

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

如有疑问,请宏观扩展。

答案 1 :(得分:1)

以下是函数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)