【发布时间】:2017-04-29 10:27:45
【问题描述】:
我的目标是在编译阶段(即在宏中)填充一个数组,并在执行阶段使用它。但是,由于某种原因,Racket 无法将宏返回的对象识别为数组。为了说明问题,显示此行为的最短代码:
(require (for-syntax math/array))
(require math/array)
(define-syntax (A stx)
(datum->syntax stx `(define a ,(array #[#[1 2] #[3 4]]))))
(A)
这个宏执行后,'a'是什么东西,但我不知道它是什么东西。它不是一个数组 ((array? a) -> #f) 也不是一个字符串,array-ref 显然无法处理它,但它打印为:(array #[#[1 2] #[3 4]])。 "swindle" 模块中的 "class-of" 声称它是 "primitive-class:unknown-primitive",值得。
我尝试过输出一个向量而不是一个数组,但它按预期工作,即结果值是一个处于执行阶段的向量。
我尝试使用“兼容性”模块中的 CommonLisp 样式 defmacro,认为这可能与 datum->syntax 转换有关,但这并没有改变。
我已经在带有 Racket 6.5 和 6.7 的 Win7 以及带有 Racket 6.7 的 Linux 上对此进行了测试 - 问题仍然存在。
有什么想法吗?
更新
感谢很好的回答和建议,我想出了以下解决方案:
(require (for-syntax math/array))
(require math/array)
(define-syntax (my-array stx)
(syntax-case stx ()
[(_ id)
(let
([arr (build-array
#(20 20)
(lambda (ind)
(let
([x (vector-ref ind 1)]
[y (vector-ref ind 0)])
(list 'some-symbol x y (* x y)))))])
(with-syntax ([syn-arr (eval (read (open-input-string (string-append "#'" (format "~v" arr)))))])
#'(define id syn-arr)))]))
(my-array A)
我不确定这是否合适 Racket(我欢迎所有关于代码改进的建议),但它是这样工作的:
数组被构建并存储在“arr”变量中。然后它被打印到字符串中,前面加上#'(这样这个字符串现在代表语法对象)并作为代码进行评估。这有效地将数组转换为语法对象,可以嵌入到宏输出中。
这种方法的优点是,每个可以被Racket写出然后读回的对象都可以通过宏输出。缺点是,有些对象不能(我在看你,自定义结构!),因此在某些情况下可能需要额外的字符串创建函数。
【问题讨论】:
标签: arrays macros scheme lisp racket