Macros OnLisp中的CONDLET宏对我来说有些不简单
我不明白下面第1个出租条款的目的Macros OnLisp中的CONDLET宏对我来说有些不简单,macros,lisp,common-lisp,Macros,Lisp,Common Lisp,我不明白下面第1个出租条款的目的 `(,(car cl) (let ,(mapcar #'cdr vars) 这是必要的,因为它没有在这里定义特定的值吗? 它只是声明局部变量。为什么要这么做 (defmacro condlet (clauses &body body) (let ((bodfn (gensym)) (vars (mapcar #'(lambda (v) (cons v (gensym)))
`(,(car cl) (let ,(mapcar #'cdr vars)
这是必要的,因为它没有在这里定义特定的值吗?
它只是声明局部变量。为什么要这么做
(defmacro condlet (clauses &body body)
(let ((bodfn (gensym))
(vars (mapcar #'(lambda (v) (cons v (gensym)))
(remove-duplicates
(mapcar #'car
(mappend #'cdr clauses))))))
`(labels ((,bodfn ,(mapcar #'car vars)
,@body))
(cond ,@(mapcar #'(lambda (cl)
(condlet-clause vars cl bodfn))
clauses)))))
(defun condlet-clause (vars cl bodfn)
`(,(car cl) (let ,(mapcar #'cdr vars)
(let ,(condlet-binds vars cl)
(,bodfn ,@(mapcar #'cdr vars))))))
(defun condlet-binds (vars cl)
(mapcar #'(lambda (bindform)
(if (consp bindform)
(cons (cdr (assoc (car bindform) vars))
(cdr bindform))))
(cdr cl)))
基于,condlet
可以这样使用:
(condlet (((= 1 2) (x 1) (y 2))
((= 1 1) (x 2) (y 1))
(t (x 3) (z 3)))
(list x y z))
请注意,正文部分中出现了三个变量,x
、y
和z
,但这些子句中的每一个只绑定两个:第一个和第二个绑定x
和y
,第三个绑定x
和z
。通过做
(let (x y z)
(let <bindings from actual clause>
(bodyfn x y z)))
mappend
不是公共Lisp的一部分。这应该是mapcan
?你能举例说明如何使用condlet
,这样我们就可以有一些好的输入数据用于宏扩展吗?@JoshuaTaylor Lisp中的所有示例代码都列在这里:@JoshuaTaylor它也不假定函数返回可变列表,与mapcan
@user1461328不同,是的,我们刚才讨论了它与mapcan
(它使用ncoc
而不是append
)的区别。主要区别在于append
复制传入列表,而ncoc
对传入列表进行变异。后者性能更高,但只能在列表为线性更新时使用;前者可以在任何地方使用。感谢您提供的详细信息。理解。
(pprint (macroexpand-1 '(condlet (((= 1 2) (x 1) (y 2))
((= 1 1) (x 2) (y 1))
(t (x 3) (z 3)))
(list x y z))))
;=>
(LABELS ((#:G973 (Y X Z) ; g973 = bodfn
(LIST X Y Z)))
(COND
((= 1 2)
(LET (#:G974 #:G975 #:G976) ; y(g974) = nil, x(g975) = nil, z(g976) = nil
(LET ((#:G975 1) (#:G974 2)) ; x = 1, y = 2
(#:G973 #:G974 #:G975 #:G976)))) ; (bodfn y x z)
((= 1 1)
(LET (#:G974 #:G975 #:G976) ; y = nil, x = nil, z = nil
(LET ((#:G975 2) (#:G974 1)) ; x = 2, y = 1
(#:G973 #:G974 #:G975 #:G976)))) ; (bodfn y x z)
(T
(LET (#:G974 #:G975 #:G976) ; y = nil, x = nil, z = nil
(LET ((#:G975 3) (#:G976 3)) ; x = 3, z = 4
(#:G973 #:G974 #:G975 #:G976)))))) ; (bodfn y x z)