Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macros OnLisp中的CONDLET宏对我来说有些不简单_Macros_Lisp_Common Lisp - Fatal编程技术网

Macros OnLisp中的CONDLET宏对我来说有些不简单

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)))

我不明白下面第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))) 
基于,
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)