macros - OnLisp 中的 CONDLET 宏对我来说并不简单

标签 macros lisp common-lisp

我不明白下面 condlet-clause 中第一个 LET 的用途。

`(,(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 ,但每个子句仅绑定(bind)两个:第一个和第二个绑定(bind) xy ,第三个绑定(bind) xz 。通过这样做

(let (x y z)
  (let <bindings from actual clause>
    (bodyfn x y z)))

宏保证 x , y ,和z全部都有默认值 nil<bindings from actual clause>将在词法上隐藏实际子句负责绑定(bind)的变量。不过,这有点简化。要了解实际发生的情况,让我们看看该示例的宏展开:

(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/

相关文章:

macros - 如何在普通 lisp 中编写宏定义宏

c++ - #定义: why uppercase?

c - 在 C 中的运行时用 #define 宏值替换字符串

c++ - 打印宏连接失败

functional-programming - 读SICP的前置条件是什么?

lisp - X 秒后中止函数 - lisp

common-lisp - 在 common lisp 中访问向量

c - 将container_of宏应用于嵌入的char数组时报告警告

lisp - 从未调用过 Lisp 函数

lisp - LISP 中的快速排序