我不明白下面第1个让入条件条款的目的。
`(,(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)))
最佳答案
根据this implementation of CONDLET
,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)))
宏保证
x
、y
和z
都有默认值nil
<bindings from actual clause>
将在词汇上隐藏实际子句负责绑定的变量。不过,这有点简单为了了解实际情况,让我们看看该示例的宏扩展:(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)
关于macros - 在OnLisp的CONDLET宏中,对我来说有些不简单的事情,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20510148/