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的函数调用=] 其中 b 和 c 被评估。
'(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)
我必须在 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的函数调用=] 其中 b 和 c 被评估。
'(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)