Thanks for the response, Jack.

I'm looking at: https://docs.racket-lang.org/reference/contmarks.html

I don't see a way to update the value of an existing key without installing 
a new mark.  Is it possible to do that?  Parameters allow you to update the 
value associated with the innermost use of `parameterize` without 
re-parameterizing.  These updates are what I'd like to isolate between 
resumes.

The idea in the example is that `(shift k k)` "throws" the continuation at 
that point up to the enclosing `reset`.  So `K` ends up bound to a 
procedure of one (unused) argument that continues where the `(shift k k)` 
left off, inside the body of the `parameterize`.  You can use continuations 
like these to implement a form of cooperative thread or coroutine, which 
can even be resumed from the same point multiple times.  However in cases 
where you're also using `parameterize`, unlike spawning a real Racket 
thread, it looks like we don't get the benefit of local parameter updates 
being isolated across multiple resumes, so each one sees any further 
updates made by other resumes, like they are sharing mutable state.  I was 
hoping to see each resume begin in the same dynamically-scoped state, 
oblivious to dynamically-scoped updates made by other resumes.

Aside from the thread-wrapping hack, I'm not sure I see a good way to 
recover isolation behavior from non-isolation-by-default (though the 
reverse doesn't seem to be a problem: if we started with 
isolation-by-default, we could recover non-isolation by installing a 
mutable box as the parameter).  An alternative is to abandon parameters 
completely and replace them with algebraic state effects (also using 
delimited continuations), but it seems like a shame to have to do that when 
parameters are already so close to the right thing.
On Thursday, July 29, 2021 at 10:25:54 PM UTC-4 jackh...@gmail.com wrote:

> I don't fully follow the example you gave because I'm not super familiar 
> with shift/reset, but would using continuation marks directly instead of 
> parameters work for your use case? Continuation marks work like what you 
> described, where data is stored directly on the stack rather than in a 
> thread cell pointed to by the stack.
>
> On Sunday, July 25, 2021 at 10:35:00 AM UTC-7 greg....@gmail.com wrote:
>
>> I'm using dynamic binding while also using delimited control operators 
>> such as shift and reset.  When shift captures the context of a 
>> `parameterize`, I'd like to be able to resume that continuation in the same 
>> context multiple times without observing modifications caused by other 
>> resumptions.
>>
>> 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.  But it 
>> looks like dynamic parameters actually rely on a shared mutable cell, in 
>> this case a thread cell.
>>
>> Knowing this, I have a strange workaround using a wrapping thread to 
>> force a distinct thread cell to be created for each resumption, providing 
>> isolation.  Is there a better way to do this?
>>
>> 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?
>>
>>
>> Here is an example, including a demonstration of the workaround:
>>
>> ```
>> #lang racket/base
>> (require racket/control)
>>
>> (define P (make-parameter #f))
>> (define (show) (displayln (P)))
>> (define (inc) (P (+ 1 (P))))
>>
>> (define (re-enter k)
>>   (define result (void))
>>   (define t (thread
>>               (lambda ()
>>                 (set! result (k (void))))))
>>   (thread-wait t)
>>   result)
>>
>>
>> (define K (reset (parameterize ((P 0))
>>                    (show)
>>                    (inc)
>>                    (shift k k)
>>                    (show)
>>                    (inc)
>>                    (P))))
>>
>> ;; The behavior that surprised me:
>> (displayln "without threads:")
>> (K) ; 2
>> (K) ; 3
>> (K) ; 4
>>
>> ;; The behavior I would like:
>> (displayln "with threads:")
>> (re-enter K) ; 5
>> (re-enter K) ; 5
>> (re-enter K) ; 5
>> ```
>>
>>
>> Program output:
>>
>> 0
>> without threads:
>> 1
>> 2
>> 2
>> 3
>> 3
>> 4
>> with threads:
>> 4
>> 5
>> 4
>> 5
>> 4
>> 5
>>
>>

-- 
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 racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/0439bf01-baac-462c-ac61-4a218a9efebcn%40googlegroups.com.

Reply via email to