对于一个程序,我试图使用这样的宏来简化我的下游代码,并避免一次又一次地重复相同的代码:
public static int[] sortArray(int[] array) {
int length = array.length;
for (int i = 0; i < length - 1; i++) {
int k = -1; // The index of last odd element
for (int j = 0; j < length - i; j++)
if (array[j] % 2 != 0) {
if (k >= 0 && array[k] > array[j]) {
int temp = array[k];
array[k] = array[j];
array[j] = temp;
}
k = j;
}
}
return array;
}
应该使用这样的列表:
(defmacro destructure (values &body body)
`(let* ((other-values (rest values))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
(progn ,@(loop for e in body collect `(,@e)))))
想法是我应该能够运行以下代码:
'(name :age 1 :len 2 :all '(1 2 3 4 5))
或者使用这样的变量:
(destructure '(name :age 1 :len 2 :all '(1 2 3 4 5))
(type-of age)
(first all))
不必每次都访问不同的元素。当然,这是一个简化的示例,但是我要处理的清单是现实要长得多。
我发现很难做到这一点。基本上,上面的代码不起作用(除非我通过设置全局变量“ values”作弊来保存我的列表,以作弊),因为宏在不扩展其应指向的列表的情况下,正以同样的方式对待符号“ values”。 / p>
另一方面,我不能使用常规函数,因为这样我传递给主体的指令会立即执行,但我必须将它们放在let中。
我对这门语言还很陌生,我相信我可能会缺少一些东西,并且可能有一种方法可以实现它。有吗?
答案 0 :(得分:4)
首先,对于您的问题,可以使用destructuring-bind
:
(destructuring-bind (name &key age len all)
'(name :age 1 :len 2 :all (1 2 3 4 5))
(list (type-of age)
(type-of len)
(type-of name)
(first all)))
⇒ (BIT (INTEGER 0 4611686018427387903) SYMBOL 1)
现在,关于您的代码的一些注意事项:
您已将对values
的引用放在反引号内,因此它不是对宏参数的引用,而是对扩展名为values
的外部变量的扩展形式的自由引用。您可能打算做什么:
(defmacro destructure (values &body body)
`(let* ((other-values ,(rest values)))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
…))
这有一个问题,就是它会从宏调用表单的外部遮盖任何名为other-values
的变量。您应该使用gensyms来避免这种情况:
(defmacro destructure (values &body body)
(let ((other-values (gensym "other-values")))
`(let* ((,other-values ,(rest values)))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
…))
关于代码模板的注释:
(progn ,@(loop for e in body collect `(,@e))
简化为
(progn ,@(loop for e in body collect e))
简化为
(progn ,@body)
,由于let
的主体已经是隐式的progn
:
,@body
最后,您的示例数据:
(name :age 1 :len 2 :all '(1 2 3 4 5))
实际上是:
(name :age 1 :len 2 :all (quote (1 2 3 4 5)))
阅读器始终将'
扩展为quote
形式。当您嵌套quote
表单时,几乎总是在做错事。
答案 1 :(得分:3)
您需要评估宏中的values变量:
? (defmacro destructure (values &body body)
`(let* ((other-values (rest ,values))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
(progn ,@body)))
DESTRUCTURE
? (destructure '(name :age 1 :len 2 :all '(1 2 3 4 5))
(print (type-of age))
(print (first all)))
;Compiler warnings :
; In an anonymous lambda form at position 0: Unused lexical variable LEN
BIT
QUOTE
QUOTE
数据中的QUOTE不是您想要的。带引号的数据不需要内部引号。
? (destructure '(name :age 1 :len 2 :all (1 2 3 4 5))
(print (type-of age))
(print (first all)))
;Compiler warnings :
; In an anonymous lambda form at position 0: Unused lexical variable LEN
BIT
1
1
它也适用于变量:
? (let ((values '(name :age 1 :len 2 :all (1 2 3 4 5))))
(destructure values
(print (type-of age))
(print (first all))))
;Compiler warnings :
; In an anonymous lambda form at position 59: Unused lexical variable LEN
BIT
1
1
?
您还可以将三个变量声明为ignorable
。这将使上面的警告消失。
要解决什么?
other-values
在正文中可见。