在编写Racket宏的过程中," 3D语法"意思?
我已经听过几次这句话了。包括一次参考宏 I 正在编写。但那是一段时间以前;我修好了,现在我无法记住我最初做错了什么。
另外:3D语法总是坏吗?或者它就像eval
(如果你认为你需要使用它,你可能错了,但在专家手中有一些有效用途)?
答案 0 :(得分:6)
语法对象通常应该只是serializable data。 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语法可以充当动态评估代码与其周围环境之间的通信通道。