[racket] Racket macro state reset
At Mon, 16 Feb 2015 14:36:16 -0500, "Paul Ojanen" wrote:
> I'm working on a macro that will have mutable state.
>
> [I'm new to macros in general, and I'm new to pattern matching in Racket and
> all things related to syntax functions and objects. I'm also still learning
> about macro expansion, compile time, run time, etc.]
In case you haven't looked at it already, this paper might be helpful:
"Composable and Compilable Macros: You Want it When?"
http://www.cs.utah.edu/plt/publications/macromod.pdf
> I was surprised that the macro's state is empty when I try to interact with
> it from the Interactions Window. Are all the compile/macro-expansion time
> definitions redefined for the Interactions Window?
Yes. Each compilation of a module starts with fresh compile-time state
for any module that it imports, including a module's own state while
the module is being compiled. The top-level (for interaction) acts as a
kind of module for that purpose.
> In the below Interactions Window dialogue, why does (acc) start referring to
> a different hashtable than ht2?
The compile-time part of the module is instantiated once when then
module is compiled, and `(acc)` expands to a mutable hash table during
that compilation. In other words, the compiled form of the module has a
specific mutable hash table for the right-hand side of `ht2`, and it's
the same hash table every time the module is instantiated. Using
`(acc)` in the interactions window, however, gets you a hash table from
a fresh compile-time instance of the module.
The fact that `datum->syntax` accepts a mutable hash table is a hole
Racket's separation of phases. We sometimes call the result "3-D
syntax", because it creates a syntax object that can't be written as
literal syntax. We haven't closed the hole, for various reasons, but
you should avoid 3-D syntax for your sanity and so that various Racket
tools (such as `raco make`) can work.
As it turns out, constructing 3-D syntax with a mutable hash table can
be particularly confusing, because the hash table will get coerced to
an immutable hash table if the code is ever marshaled to bytes, such as
in a ".zo" file. So, it will seem to work for slightly longer than 3-D
syntax usually seems to work, but it really doesn't work.
> Here's my stripped-down code:
>
> #lang racket
>
> (begin-for-syntax
> (define ht (make-hash))
> )
>
> (define-syntax (acc stx)
> (syntax-case stx ()
> [(_ (f (fn x) body)) (begin
>
> ; Record what was defined within the acc block
> (hash-set! ht
> (syntax->datum (syntax fn))
> (syntax->datum (syntax body)))
>
> ; Define it in the real evironment
> #'(f (fn x) body))]
>
> [(_) (datum->syntax #'acc ht)] ; see what's been recorded
> ))
>
> ; Define a sqr function
> (acc
> (define (sqr2 x) (* x x))
> )
>
> ; Try the sqr function
> (sqr2 5)
>
> ; See what was recorded by the macro
> (acc)
>
> ; Bind a run-time variable to the macro's hashtable
> (define ht2 (acc))
>
> --------Interactions Window dialogue
> 25
> '#hash((sqr2 . (* x x)))
> > (sqr2 5)
> 25
> > (acc) ;the hashtable is empty
> '#hash()
> > ht2 ;no, it's not
> '#hash((sqr2 . (* x x)))
> > (acc (define (sqr3 x) (* x x)))
> > (acc)
> '#hash((sqr3 . (* x x)))
> > ht2
> '#hash((sqr2 . (* x x)))
>
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users