Thanks, I think that makes sense.

Is the `parameter * thread * parameterization -> box` part implemented as 
something like a global weak-hash, or is it built directly into the stack 
representation?


Continuing the other conversation for a moment with a code reference to 
explain to my future self, or anyone else curious, what I meant by 
"algebraic state effects". Here's a simple implementation with a couple 
examples:

```
#lang racket/base
(require racket/control)

(struct state-parameter (tag)
        #:property prop:procedure
        (case-lambda
          ((self)   (shift-at (state-parameter-tag self) k (lambda (x) ((k 
x)      x))))
          ((self v) (shift-at (state-parameter-tag self) k (lambda (_) ((k 
(void)) v))))))

;; Analogous to make-parameter, but without a default value
(define (make-state-parameter)
  (state-parameter (make-continuation-prompt-tag)))

(define-syntax state-parameterize*
  (syntax-rules ()
    ((_ ()         body ...)
     (let () body ...))
    ((_ ((e.p e))  body ...)
     (let ((p e.p) (x e))
       ((reset-at (state-parameter-tag p)
                  (let ((result (begin body ...)))
                    (lambda (_) result)))
        x)))
    ((_ (b bs ...) body ...)
     (state-parameterize* (b) (state-parameterize* (bs ...) body ...)))))

(define-syntax state-parameterize-etc
  (syntax-rules ()
    ((_ final       ()               body ...)
     (state-parameterize* final body ...))
    ((_ (final ...) ((e.p e) bs ...) body ...)
     (let ((p e.p) (x e))
       (state-parameterize-etc (final ... (p x)) (bs ...) body ...)))))

;; Analogous to parameterize
(define-syntax-rule (state-parameterize etc ...) (state-parameterize-etc () 
etc ...))


;; The same kind of single state example
(define P (make-state-parameter))
(define (show) (displayln (P)))
(define (inc) (P (+ 1 (P))))

(define K
  (reset
    (state-parameterize ((P 0))
      (show)
      (inc)
      (shift k k)
      (show)
      (inc)
      (P))))

(displayln "with algebraic state:")
(K) ; 2
(K) ; 2
(K) ; 2


;; An example with multiple states
(define R (make-state-parameter))
(define Q (make-state-parameter))
(define (show2) (displayln `(R: ,(R) Q: ,(Q))))
(define (inc2) (R (+ 1 (R))) (Q (- (Q) 1)))

(define J
  (reset
    (state-parameterize ((R 0) (Q 0))
      (show2)
      (inc2)
      (shift k k)
      (show2)
      (inc2)
      (list (R) (Q)))))

(displayln "with multiple algebraic states:")
(J) ; 2 -2
(J) ; 2 -2
(J) ; 2 -2
```
On Friday, July 30, 2021 at 11:04:09 AM UTC-4 Matthew Flatt wrote:

> At Sun, 25 Jul 2021 10:35:00 -0700 (PDT), Greg Rosenblatt wrote:
> > I was surprised that subsequent re-entries can observe modifications 
> from 
> > the earlier ones, since my mental model of dynamic parameters was that 
> > their values were retrieved from a fresh dynamic calling context, whose 
> > frames are copied each time the delimited continuation is invoked.
> > [...]
> > I'm also interested in the reasons behind the current design. Is there a 
> > downside to storing parameter bindings directly on the stack, rather 
> than 
> > in a thread cell pointed to by the stack?
>
> I think I see what you mean here, but I also think that idea would run
> into trouble. A (delimited) continuation is invoked every time you
> return a value to a continuation, whether or not that continuation was
> captured by `call/cc`. Internally, in fact, the current continuation
> frequently gets reified and invoked through returns. I think it would
> create a bad interaction among features if a distinction were made
> between explicit (applying a captured continuation) and implicit
> (returning a value) continuation invocations.
>
> > I'd like to be able to resume that continuation in the same context
> > multiple times without observing modifications caused by other
> > resumptions. [...] But it looks like dynamic parameters actually rely
> > on a shared mutable cell, in this case a thread cell.
>
> Yes, parameters are based on a mapping
>
> parameter * thread * paramterizization -> box
>
> When you set or look up a parameter value, the thread part comes from
> `current-thread`, and the parameterization part comes from a
> continuation mark. So, that's why capture and restore within a thread
> sees the same box, but capture and restore of a continuation in a
> different thread gets a different box.
>
> I think you want to introduce a notion of "resume" that replaces the
> thread part of the mapping, plus a replacement notion of
> parameterization. That is, each time you resume, the applied
> continuation should extend one that maps an internal mark to the
> current resume. A replacement for `parameterize` would also install a
> mark (with a different key) to identify a "parameterization", while
> also mapping the parameter * parameterization * resume to a fresh box.
> When you look up a parameter value or mutate a parameter, the current
> mark for the resume and the current mark for the parameterization would
> let you find the right box.
>
> It may be best to have a "parameterization" specific to each
> "parameter" (i.e., a separate mark for each parameter), instead of
> aggregating them in the way `parameterize` does. In the case of threads
> and parameters, aggregation makes it easier to create a new thread that
> inherits the parameterization of the creating thread. But if you don't
> need that, aggregation also works less well with delimited continuation
> capture, because `parameterize` captures all parameter values and not
> just the ones that are set in the `parameterize` form.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/1d037d3f-83e6-45b2-b215-ea574ed586dcn%40googlegroups.com.

Reply via email to