Hi, Racket Discourse.
I am experimenting with ways of exposing mutable variables to programmers within the body of procedures which themselves build-up objects (by which I am implying, that it is difficult to percolate the two sets of results up the nested calls without introducing a lot of machinery just for that).
One idea I had, was to use temporary parameters; surprisingly, I did not realize (although it is obvious in hindsight) one could create and parameterize parameters on the fly.
Take this macro, for example:
(define-syntax (let-parameters stx)
(syntax-parse stx
[(_ ([name:id init:expr] ...) body:expr ...)
#'(let ([name (make-parameter #false)] ...)
(parameterize ([name init] ...)
body ...))]))
Which then might be used something like this:
(define page
'(html
(body (p ([class "baz"])
"foo" "bat")
(p "bar" (br) "qux"))
(br)
(body (p ([class "zab"]
[id "1"])
"foo" "tab")
(p "rab" (br) "xuq"))))
(let-parameters ([tag-indexes (hash)])
(values
(with-xe '(html body . p)
(lambda (tag p-body)
(with-parameters (tag-indexes)
(define index (hash-count tag-indexes))
(hash-set tag-indexes index tag))
(println (cons tag p-body))
p-body)
page)
{tag-indexes}))
; '(p "foo" "bat")
; '(p "bar" (br) "qux")
; '(p "foo" "tab")
; '(p "rab" (br) "xuq")
;=> '(html (body (p ((class "baz")) "foo" "bat") (p "bar" (br) "qux")) (br) (body (p ((class "zab") (id "1")) "foo" "tab") (p "rab" (br) "xuq")))
;=> '#hash((0 . p) (1 . p) (2 . p) (3 . p))
The with-parameters
basically desugars to:
{parameter ... {parameter} ...}
assigning the results of the body to the parameters without needing to unwrap them.
Now, this is very cute, but is this silly?
Technically, all I am doing is avoiding the set!
--which could be wrapped in similar machinery for the same effect. Moreover, this allows "spooky action at a distance", since if the parameters escape the immediate body of the bindings, they could be used to change the "locally global" values. Which could be cool, but also terrible.
Have you ever used temporary parameters before?