Syntaxobjekte sollen normalerweise nur serializable data sein. Die 3D-Syntax schwächt diese Bedingung: Sie ermöglicht es uns, beliebige Werte einzuschleusen und nicht nur reine Daten. Das macht sie zu "3d": Sie sind Werte, die über die normalen flachen Dinge hinausgehen, die man von Syntaxobjekten erwarten würde.
Zum Beispiel können wir in lambda
Werte schleichen!
#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)))
tut dies in der Regel eine schlechte Sache, weil das Vorhandensein solchen Wertes bedeutet wahrscheinlich einen unbegründeten Versuch, Informationen über Phasen der Kompilierung zu lecken. Das Ergebnis ist wahrscheinlich nicht separat kompilierbar. Wenn Sie einen Fehler sehen, die wie etwas klingt:
write: cannot marshal value that is embedded in compiled code value
dann ist das höchstwahrscheinlich auf ein Makro ein Stück 3D-Syntax erzeugt zu haben, die nicht zu Bytecode serialisiert werden kann.
Manchmal, in seltenen Situationen, wollen wir wirklich 3D-Syntax, oft in dynamischen Bewertungskontexten. Als ein konkretes Beispiel möchte ein Debugger in DrRacket vielleicht die Syntax eines Programms annotieren, so dass Funktionsanwendungen direkt in Funktionen des Debuggers zurückrufen, so dass wir Dinge wie eine interaktive Codeüberdeckungseinfärbung im Programmeditor tun können. In diesem Sinne kann die 3d-Syntax als Kommunikationskanal zwischen dynamisch evaluiertem Code und seiner Umgebung dienen.
In Zukunft wird vielleicht alles gut dokumentiert sein! +1 für die Schwierigkeit. Sieht für mich nach einer guten Kopfgeldfrage aus. Das einzige, was ich relevant finden konnte, war diese Diskussion: http://lists.racket-lang.org/dev/archive/2013-Januar/011637.html – jdero