13

在编写 Racket 宏的上下文中,“3D 语法”是什么意思?

这句话我听过几次。包括一次引用正在编写的宏。但那是不久前的事了;我修复了它,现在我不记得我最初做错了什么。

另外:3D 语法总是不好的吗?还是像eval(如果您认为需要使用它,您可能错了,但专家手中有一些有效的用途)?

4

1 回答 1

10

语法对象通常应该只是可序列化的数据。3D 语法削弱了这种情况:它允许我们潜入任意值,而不仅仅是普通数据。这就是使它们成为“3d”的原因:它们是超出您对语法对象所期望的常规平面事物的值。

例如,我们可以偷偷输入lambda值!

#lang racket

(define ns (make-base-namespace))
(define (set-next! n)
  (parameterize ([current-namespace ns])
    (eval #`(define next #,n))))    ;; <--  3d-syntax here

(define (compute s)
  (parameterize ([current-namespace ns])
    (eval s)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define counter 0)
(set-next! (lambda ()
             (set! counter (add1 counter))
             counter))

(compute '(+ (next)
             (next)
             (next)
             (next)))

这样做通常是一件坏事,因为这些值的存在可能意味着在编译阶段泄漏信息的毫无根据的尝试。结果是可能无法单独编译的东西。如果您看到类似于以下内容的错误:

write: cannot marshal value that is embedded in compiled code value

那么这很可能是由于宏产生了一段无法序列化为字节码的 3d 语法。

有时,在极少数情况下,我们确实需要 3d 语法,通常是在动态评估上下文中。举个具体的例子,DrRacket 中的调试器可能想要注释程序的语法,以便函数应用程序直接回调到调试器的函数中,这样我们就可以在程序编辑器中进行交互式代码覆盖着色等操作。从这个意义上说,3d 语法可以充当动态评估代码与其周围环境之间的通信通道。

于 2013-07-02T23:37:59.763 回答