Here is an implementation of parameters and parameterizations in Racket. This is a simplified version of the code in racket/src/cs/rumble/parameter.ss.
;; A MyParamz is (hasheq MyParam ThreadCell)
;; Rather than having one huge, changing hash for the initial
;; parameterization, the initial thread cell for a parameter is
;; stored in the parameter itself.
;; A MyParam is (myparam ThreadCell)
(struct myparam (init-cell)
#:property prop:procedure
(case-lambda
[(self) (thread-cell-ref (get-param-cell self))]
[(self newval) (thread-cell-set! (get-param-cell self) newval)]))
;; make-myparam : Any -> MyParam
(define (make-myparam init-val)
(myparam (make-thread-cell init-val #t)))
;; The 'myparamz continuation mark key is mapped to MyParamz values.
;; current-myparamz : -> MyParamz
(define (current-myparamz)
(or (continuation-mark-set-first #f 'myparamz) (hasheq)))
;; call-with-myparamz : MyParamz (-> Any) -> Any
(define (call-with-myparamz mypz proc)
(with-continuation-mark 'myparamz mypz (proc)))
;; (myparameterize ((Expr[MyParam] Expr) ...) Body ...) : Expr
(define-syntax-rule (myparameterize ((myp val) ...) body ...)
(call-with-myparamz
(hash-set* (current-myparamz) (~@ myp (make-thread-cell val #t)) ...)
(lambda () body ...)))
;; get-param-cell : MyParam -> ThreadCell
(define (get-param-cell myp)
;; If the current myparamz has an updated mapping, use that;
;; otherwise, use the myparam's original thread cell.
(or (hash-ref (current-myparamz) myp #f)
(myparam-init-cell myp)))
And here is the recent example translated to use that implementation. I've also added some more printing.
(define users (make-myparam '()))
(users (list "bob"))
(define outer (current-myparamz))
(printf "1: outer = ~v\n" outer) ;; => (hasheq)
(myparameterize ([users (list "alice")]) ; myparameterize
(define inner (current-myparamz))
(printf "2: inner = ~v\n" inner) ;; => (hasheq users #<thread-cell>)
(printf "3: users = ~v\n" (users)) ;; => '("alice")
(call-with-myparamz
inner
(lambda ()
;; => #<thread-cell>
(printf "4a: (current-myparamz) maps users to ~v\n"
(hash-ref (current-myparamz) users #f))
;; => '("alice")
(printf "4b: inner users = ~v\n" (users))))
(call-with-myparamz
outer
(lambda ()
;; => #f
(printf "5a: (current-myparamz) maps users to ~v\n"
(hash-ref (current-myparamz) users #f))
;; => '("bob"), value in initial thread cell
(printf "5b: outer users = ~v\n" (users)))))
No, it doesn't capture the values of the parameters. It only captures the mapping of parameters to thread cells.