我不明白下面第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 CONDLETcondlet可以这样使用:

(condlet (((= 1 2) (x 1) (y 2))
          ((= 1 1) (x 2) (y 1))
          (t (x 3) (z 3)))
  (list x y z))

注意,有三个变量出现在主体部分,xyz,但是这些子句中的每一个只绑定两个:第一个和第二个绑定xy,第三个绑定xz通过做
(let (x y z)
  (let <bindings from actual clause>
    (bodyfn x y z)))

宏保证xyz都有默认值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/

10-12 14:12