gpt4 book ai didi

arrays - Racket :宏输出一些奇怪的东西而不是数组

转载 作者:太空宇宙 更新时间:2023-11-03 18:46:40 26 4
gpt4 key购买 nike

我的目标是在编译阶段(即在宏中)填充一个数组,并在执行阶段使用它。但是,出于某种原因,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,认为这可能与数据->语法转换有关,但这并没有改变。

我已经在带有 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读回的对象都可以通过宏输出。缺点是,有些对象不能(我正在看着你,自定义结构!)因此在某些情况下可能需要额外的字符串创建函数。

最佳答案

首先,不要那样使用datum->syntax。你在那里丢弃了所有卫生信息,所以如果有人使用不同的语言,其中 define 被称为其他东西(例如 def),那将不起作用.有关 Racket 宏的原则性介绍,请考虑阅读 Fear of Macros .

其次,这里的问题是您正在创建有时称为 “3D syntax” 的内容。 . 3D 语法在这种情况下应该是一个错误,但要点是只有一个 small set of things。您可以安全地将其放入语法对象中:

  • 一个符号
  • 一个数字
  • 一个 bool 值
  • 一个角色
  • 一个字符串
  • 空列表
  • 一对两段的有效语法
  • 有效语法的向量
  • 一盒有效语法
  • 有效语法键和值的哈希表
  • 包含唯一有效语法的预制结构

任何其他都是“3D语法”,作为宏的输出是非法的。值得注意的是,math/array 中的数组是不允许的。

这似乎是一个相当极端的限制,但重点是上面的列表只是可以在编译代码 中结束的事物的列表。 Racket 不知道如何将任意内容序列化为字节码,这是合理的:例如,在编译代码中嵌入闭包没有多大意义。但是,生成一个创建数组的表达式是完全合理的,这就是您应该在此处执行的操作。

更恰本地编写你的宏,你会得到这样的东西:

#lang racket

(require math/array)

(define-syntax (define-simple-array stx)
(syntax-case stx ()
[(_ id)
#'(define id (array #(#(1 2) #(3 4))))]))

(define-simple-array x)

现在,x(数组#[#[1 2] #[3 4]])。请注意,您可以删除 math/arrayfor-syntax 导入,因为您在编译时不再使用它,这是有道理的:宏只是操作代码位.您只需要在运行时使用 math/array 来创建您最终得到的实际值。

关于arrays - Racket :宏输出一些奇怪的东西而不是数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41136717/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com