Discussion:
[racket] Racket macro state reset
Paul Ojanen
2015-02-16 19:36:16 UTC
Permalink
Hello,



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.]



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?



In the below Interactions Window dialogue, why does (acc) start referring to
a different hashtable than ht2?



Regards,

Paul



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)))
Matthew Flatt
2015-02-16 19:58:49 UTC
Permalink
Post by Paul Ojanen
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
Post by Paul Ojanen
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.
Post by Paul Ojanen
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.
Post by Paul Ojanen
#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)))
Post by Paul Ojanen
(sqr2 5)
25
Post by Paul Ojanen
(acc) ;the hashtable is empty
'#hash()
Post by Paul Ojanen
ht2 ;no, it's not
'#hash((sqr2 . (* x x)))
Post by Paul Ojanen
(acc (define (sqr3 x) (* x x)))
(acc)
'#hash((sqr3 . (* x x)))
Post by Paul Ojanen
ht2
'#hash((sqr2 . (* x x)))
____________________
http://lists.racket-lang.org/users
____________________
Racket Users list:
http://lists.racket-lang.org/users

Loading...