在编写Racket宏的过程中,"3D语法"是什么意思?
我已经听过几次这句话了.包括一次参考我写的宏.但那是一段时间以前; 我修好了,现在我不记得我到底做错了什么.
另外:3D语法总是坏的吗?或者是它eval(如果你认为你需要使用它,你可能错了,但在专家手中有一些有效的用途)?
语法对象通常应该只是可序列化的数据.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)))
Run Code Online (Sandbox Code Playgroud)
这样做通常是件坏事,因为这些值的存在可能意味着在编译阶段泄漏信息的无根据的尝试.结果是可能无法单独编译的结果.如果您看到一个类似于以下内容的错误:
write: cannot marshal value that is embedded in compiled code value
Run Code Online (Sandbox Code Playgroud)
然后,这很可能是由于宏生成了一段无法序列化为字节码的3d语法.
有时候,在极少数情况下,我们确实需要3d语法,通常是在动态评估环境中.作为一个具体的例子,DrRacket中的调试器可能想要注释程序的语法,以便函数应用程序直接调用回调试器的函数,以便我们可以在程序编辑器中执行交互式代码覆盖着色等操作.从这个意义上讲,3d语法可以充当动态评估代码与其周围环境之间的通信通道.