我必须在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)))
所有这些调用都以相同的结果结束。
答案 0 :(得分:2)
(a b c)
a
未绑定到宏,则表单是对 a 的函数调用,其中 b <评估/ em>和 c 。 '(a b c)
,a.k.a。(quote (a b c))
quote
,然后是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)