Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/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 在Common Lisp中将列表正确传递给宏_Macros_Common Lisp - Fatal编程技术网

Macros 在Common Lisp中将列表正确传递给宏

Macros 在Common Lisp中将列表正确传递给宏,macros,common-lisp,Macros,Common Lisp,我编写了一个宏来执行多个嵌套循环。我知道还有其他工具可以做到这一点,但我正在尝试学习如何编写宏,这似乎是一个很好的用例。它也起作用(有点): 运行: (macroexpand-1 '(dotimes-nested '(2 3 5) #'(lambda (x y z) (format t "~A, ~A, ~A~%" x y z)))) 产出: (DOTIMES (#:G731 2 #:G731) (DOTIMES (#:G732 3 #:G732)

我编写了一个宏来执行多个嵌套循环。我知道还有其他工具可以做到这一点,但我正在尝试学习如何编写宏,这似乎是一个很好的用例。它也起作用(有点):

运行:

(macroexpand-1 '(dotimes-nested '(2 3 5)
                #'(lambda (x y z) (format t "~A, ~A, ~A~%" x y z))))
产出:

(DOTIMES (#:G731 2 #:G731)
  (DOTIMES (#:G732 3 #:G732)
    (DOTIMES (#:G733 5 #:G733)
      (FUNCALL #'(LAMBDA (X Y Z) (FORMAT T "~A, ~A, ~A~%" X Y Z)) #:G731 #:G732
               #:G733))))
并按如下方式调用宏:

(dotimes-nested '(2 3 5)
                #'(lambda (x y z) (format t "~A, ~A, ~A~%" x y z)))
(let ((dims '(3 4)))
    (dotimes-nested dims
                #'(lambda (x y) (format t "~A, ~A~%" x y))))
正确返回我期望的结果:

0, 0, 0
0, 0, 1
0, 0, 2
0, 0, 3
0, 0, 4
0, 1, 0
0, 1, 1
0, 1, 2
0, 1, 3
0, 1, 4
0, 2, 0
0, 2, 1
0, 2, 2
0, 2, 3
0, 2, 4
1, 0, 0
1, 0, 1
1, 0, 2
1, 0, 3
1, 0, 4
1, 1, 0
1, 1, 1
1, 1, 2
1, 1, 3
1, 1, 4
1, 2, 0
1, 2, 1
1, 2, 2
1, 2, 3
1, 2, 4
2
但是,如果我这样称呼它:

(dotimes-nested '(2 3 5)
                #'(lambda (x y z) (format t "~A, ~A, ~A~%" x y z)))
(let ((dims '(3 4)))
    (dotimes-nested dims
                #'(lambda (x y) (format t "~A, ~A~%" x y))))
我得到一个错误:

; in: LET ((DIMS '(3 4)))
;     (DOTIMES-NESTED DIMS #'(LAMBDA (X Y) (FORMAT T "~A, ~A~%" X Y)))
; 
; caught ERROR:
;   during macroexpansion of (DOTIMES-NESTED DIMS #'(LAMBDA # #)). Use
;   *BREAK-ON-SIGNALS* to intercept.
;   
;    The value DIMS is not of type LIST.

;     (LET ((DIMS '(3 4)))
;       (DOTIMES-NESTED DIMS #'(LAMBDA (X Y) (FORMAT T "~A, ~A~%" X Y))))
; 
; caught STYLE-WARNING:
;   The variable DIMS is defined but never used.
; 
; compilation unit finished
;   caught 1 ERROR condition
;   caught 1 STYLE-WARNING condition
如何传入一个不是作为符号而是作为值的变量?我应该在宏中使用、?但我不知道怎么做。还有,这两种情况是如何工作的,a:使用文字'(34)调用宏,b:传递绑定到列表的符号'(34)?我需要为每个宏分别设置宏吗

最后,我还有第二个问题。
当我为nlist传入一个文本时,我必须使用
(第二个nlist)
来获取列表值。我理解这是因为
”(34)
在发送到宏之前被扩展到
(引用(34))
。这是正确的假设吗?如果是这样的话,这是一种常规做法,即使用传递给宏的文本列表的第二个值吗?

宏在编译或运行代码之前展开。但是,变量
变暗
仅在运行代码时存在。给定给宏的参数是文字数据,因此

(dotimes-nested dims ...)
DIMS
不是对变量的引用(该变量尚不存在),而只是一个符号

调用宏时也没有必要引用列表,因为它是文本数据。因此,您应该像
(dotimes嵌套(2 3 4)…)
那样调用它(并且不需要删除宏中的任何内容)

如果确实需要能够为维度使用(运行时)变量,则应使用常规函数而不是宏。比如:

(defun dotimes-nested (nlist function)
  (labels ((rec (nlist args)
             (if (endp nlist)
                 (apply function (reverse args))
                 (destructuring-bind (first . rest) nlist
                   (dotimes (i first)
                     (rec rest (cons i args)))))))
    (rec nlist nil)))

CL-USER> (let ((dims '(3 4)))
           (dotimes-nested dims
                           #'(lambda (x y) (format t "~A, ~A~%" x y))))
0, 0
0, 1
0, 2
0, 3
1, 0
1, 1
1, 2
1, 3
2, 0
2, 1
2, 2
2, 3
NIL
(dotimes-nested dims
                #'(lambda (x y) (format t "~A, ~A~%" x y))))

在您使用宏时,我发现您引用了文字列表,在您的实现中,您实际应用了带有注释的
second
;从nlist的开头删除引号

宏接受代码输入并将宏函数应用于那些未计算的表达式,即仅引用表面语法的纯数据,结果是新代码。然后,可以在使用宏的每个地方使用宏来替换此代码

膨胀只发生一次。通常,当存储函数时,函数中的所有宏都会展开,并且在使用函数时,宏的任何痕迹都不存在

当你有类似于:

(defun dotimes-nested (nlist function)
  (labels ((rec (nlist args)
             (if (endp nlist)
                 (apply function (reverse args))
                 (destructuring-bind (first . rest) nlist
                   (dotimes (i first)
                     (rec rest (cons i args)))))))
    (rec nlist nil)))

CL-USER> (let ((dims '(3 4)))
           (dotimes-nested dims
                           #'(lambda (x y) (format t "~A, ~A~%" x y))))
0, 0
0, 1
0, 2
0, 3
1, 0
1, 1
1, 2
1, 3
2, 0
2, 1
2, 2
2, 3
NIL
(dotimes-nested dims
                #'(lambda (x y) (format t "~A, ~A~%" x y))))
宏获取符号
dims
。然后,生成的代码应该具有
dims
,这样在运行时,由于您不知道宏展开时可能是什么,因此ebently会计算为一个列表

我会这样做:

(dotimes* ((a 3) (b 2) (c 10))
  (format t "~A, ~A, ~A~%" a b c))

(defmacro dotimes* ((&rest binding-initials) &body body)
  (loop :for (binding initial) :in (reverse binding-initials)
        :for result := `(dotimes (,binding ,initial nil) ,@body) 
                    :then `(dotimes (,binding ,initial nil) ,result)
        :finally (return result)))
这样做的好处是,您可以在此处使用变量:

(defparameter *x* 10) 
(defparameter *y* 10)
(dotimes* ((x *x*) (y *y*))
  (format t "(~a,~a)~%" x y))
如果你有一个动态数量的变量,那么把它变成一个函数,就像@kiiski的答案一样,将是一个更好的匹配