Am Sa., 19. Nov. 2022 um 08:04 Uhr schrieb Shiro Kawai <shiro.ka...@gmail.com>: > > Yup, that nested parameterize example gives different results. > Racket, Gauche-release: a:1 b:1 c:2 > Srfi-226 ref.impl. , Gauche-HEAD: a:1 b:1 c:1
Can you recheck? The nested parameterize (with the N parameterization inside reset) gives a:1 b:1 c:1 on Racket 8.2 here. > > The Racket model is explainable with dynamic-wind setting/resetting dynamic > values of specified parameters (and that's how Gauche-release handles them). > > I feel srfi-226 ref impl model is easier to understand (just assuming a > continuation prompt remembers all the dynamic state). However, we don't want > the behavior of two implementation strategies to differ. > > Furthermore, this means that any dynamic state that is managed either by > dynamic-wind or by continuations marks, depending on implementations, can > behave differently, doesn't it? > > > > > > > > > > On Fri, Nov 18, 2022 at 8:47 PM Marc Nieper-Wißkirchen > <marc.nie...@gmail.com> wrote: >> >> Am Sa., 19. Nov. 2022 um 01:04 Uhr schrieb Shiro Kawai >> <shiro.ka...@gmail.com>: >> > >> > I'm inclined to the reference implementation behavior; the last example >> > you show seems very confusing, especially that the dynamic value of m >> > retrieved in seemingly the same dynamic environment (on the prompt) is >> > affected by the parameterization of unrelated parameters. In general you >> > wound't know what reparameterization is done during the inner calls. >> > >> > On the other hand, the behavior of Racket (and the current version of >> > Gauche) can be explained with dynamic-wind. >> > >> > ``` >> > (define c #f) >> > >> > (define (foo) >> > (dynamic-wind >> > (lambda () (print 'pre1)) >> > (lambda () >> > (reset >> > (print 'pre2) >> > (shift k (print 'cont) (set! c k)) >> > (print 'post2))) >> > (lambda () (print 'post1)))) >> > >> > (define (bar) >> > (dynamic-wind >> > (lambda () (print 'pre3)) >> > (lambda () (c #f)) >> > (lambda () (print 'post3)))) >> > ``` >> > >> > All implementations (Racket, srfi-226 reference impl, Gauche release, >> > Gauche HEAD) agree that what handlers are called: >> > >> > > (foo) >> > pre1 >> > pre2 >> > cont >> > post1 >> > >> > > (bar) >> > pre3 >> > post2 >> > post3 >> > >> > If parameterization is implemented by dynamic-wind, the invocation of the >> > delimited continuation won't restore dynamic values of parameters when >> > reset is called (which would've been done by pre1). >> >> Compare this to my example with the nested parameterization where the >> dynamic value of the outer parameter was also restored. To make this >> explainable with dynamic-wind, setting one parameter through >> dynamic-wind would have to set all parameters: >> >> This here prints a:1 b:1 c:1: >> >> (define (print . xs) (for-each display xs) (newline)) >> >> (define m (make-parameter 0)) >> (define n (make-parameter 0)) >> >> (define c #f) >> >> (define (foo) >> (parameterize ((m 1)) >> (reset >> (parameterize ((n 1)) >> (print 'a: (m)) >> (shift k (print 'b: (m)) (set! c k)) >> (print 'c: (m)))))) >> >> (define (bar) >> (parameterize ((m 2)) >> (c #f))) >> >> (foo) >> (bar) >> >> > >> > >> > >> > >> > >> > On Fri, Nov 18, 2022 at 11:28 AM Marc Nieper-Wißkirchen >> > <marc.nie...@gmail.com> wrote: >> >> >> >> Am Fr., 18. Nov. 2022 um 22:12 Uhr schrieb Marc Nieper-Wißkirchen >> >> <marc.nie...@gmail.com>: >> >> > >> >> > At first sight, Racket's behavior looks strange (tested with 8.2): >> >> > >> >> > This expression >> >> > >> >> > (let ((m (make-parameter 0)) >> >> > (n (make-parameter 0))) >> >> > (define k >> >> > (parameterize ((m 1)) >> >> > (call-with-continuation-prompt >> >> > (lambda () >> >> > (parameterize () >> >> > ((call-with-composable-continuation >> >> > (lambda (k) >> >> > (lambda () k))))))))) >> >> > (k (lambda () (values (m) (n))))) >> >> > >> >> > evaluates to the values 0 0. The following expression, however, >> >> > >> >> > (let ((m (make-parameter 0)) >> >> > (n (make-parameter 0))) >> >> > (define k >> >> > (parameterize ((m 1)) >> >> > (call-with-continuation-prompt >> >> > (lambda () >> >> > (parameterize ((n 1)) >> >> > ((call-with-composable-continuation >> >> > (lambda (k) >> >> > (lambda () k))))))))) >> >> > (k (lambda () (values (m) (n))))) >> >> > >> >> > evaluates to the values 1 1. >> >> > >> >> > The only difference is that the inner parameterization is not trivial. >> >> > >> >> > It seems to be that each non-trivial parameterize installs a new >> >> > continuation mark (holding the complete new parameterization). This >> >> > is captured by c-w-c-c. However, when there is no non-trivial >> >> > parameterize, no continuation mark about parameterizations is >> >> > installed in the frames that are captured, and so reinstalling the >> >> > delimited continuation does not restore the relevant continuation >> >> > marks. >> >> > >> >> > Actually, this model happens to coincide with my wording in SRFI 226: >> >> > "Conceptually, each continuation contains at least one otherwise >> >> > inaccessible parameterization continuation mark, whose value is a >> >> > parameterization. The parameterization of a continuation is the value >> >> > of the most recent parameterization continuation mark in the >> >> > continuation. The parameterization of the current continuation is the >> >> > current parameterization. The (current) parameterization can >> >> > conceptually be seen as part of the dynamic environment." >> >> > >> >> > If I take this seriously, my sample implementation has to be corrected. >> >> >> >> PS I would like to hear some opinions about it. I think the sample >> >> implementation's behavior (namely, to record the current >> >> parameterization and the current exception handler stack at each >> >> prompt so that it will be captured) makes more sense than what I wrote >> >> literally (and what is Racket's behavior). >> >> >> >> > >> >> > Am Fr., 18. Nov. 2022 um 20:57 Uhr schrieb Marc Nieper-Wißkirchen >> >> > <marc.nie...@gmail.com>: >> >> > > >> >> > > Here is an example using only the primitives: >> >> > > >> >> > > (let ((m (make-parameter 0))) >> >> > > ((parameterize ((m 4)) >> >> > > (call-with-continuation-prompt >> >> > > (lambda () >> >> > > ((call-with-composable-continuation >> >> > > (lambda (k) >> >> > > (abort-current-continuation >> >> > > (default-continuation-prompt-tag) >> >> > > (lambda () k)))))))) >> >> > > m)) >> >> > > >> >> > > In Racket, it evaluates to 0 and not to 4. >> >> > > >> >> > > Am Fr., 18. Nov. 2022 um 20:51 Uhr schrieb Shiro Kawai >> >> > > <shiro.ka...@gmail.com>: >> >> > > > >> >> > > > Racket v8.6 behaves the same way. >> >> > > > >> >> > > > On Fri, Nov 18, 2022 at 9:29 AM Shiro Kawai <shiro.ka...@gmail.com> >> >> > > > wrote: >> >> > > >> >> >> > > >> I used Racket v7.2, and here's the full transcription. I'm going >> >> > > >> to check with the newest Racket. >> >> > > >> >> >> > > >> shiro@scherzo:~/src/srfi-226$ racket >> >> > > >> Welcome to Racket v7.2. >> >> > > >> > (require racket/control) >> >> > > >> > (define (print . xs) (for-each display xs) (newline)) >> >> > > >> > (define m (make-parameter 0)) >> >> > > >> > (define c #f) >> >> > > >> > (define (foo) >> >> > > >> (parameterize ((m 1)) >> >> > > >> (reset >> >> > > >> (print 'a: (m)) >> >> > > >> (shift k (print 'b: (m)) (set! c k)) >> >> > > >> (print 'c: (m))))) >> >> > > >> > (define (bar) >> >> > > >> (parameterize ((m 2)) >> >> > > >> (c #f))) >> >> > > >> > (foo) >> >> > > >> a:1 >> >> > > >> b:1 >> >> > > >> > (bar) >> >> > > >> c:2 >> >> > > >> >> >> > > >> >> >> > > >> On Fri, Nov 18, 2022 at 9:26 AM Marc Nieper-Wißkirchen >> >> > > >> <marc.nie...@gmail.com> wrote: >> >> > > >>> >> >> > > >>> Thanks for the report, Shiro! >> >> > > >>> >> >> > > >>> I have to investigate Racket's behavior. In 11.3.2 of the Racket >> >> > > >>> reference, it says: "If a continuation is captured during the >> >> > > >>> evaluation of parameterize, invoking the continuation effectively >> >> > > >>> re-introduces the parameterization, since a parameterization is >> >> > > >>> associated to a continuation via a continuation mark (see >> >> > > >>> Continuation >> >> > > >>> Marks) using a private key." This seems to be consistent with >> >> > > >>> SRFI >> >> > > >>> 226 and its sample implementation, but not consistent with your >> >> > > >>> Racket >> >> > > >>> experiments. >> >> > > >>> >> >> > > >>> Am Fr., 18. Nov. 2022 um 20:07 Uhr schrieb Shiro Kawai >> >> > > >>> <shiro.ka...@gmail.com>: >> >> > > >>> > >> >> > > >>> > It seems that there's a disagreement in how a delimited >> >> > > >>> > continuation captures dynamic environment, between Racket and >> >> > > >>> > srfi-226. >> >> > > >>> > >> >> > > >>> > Suppose the following code: >> >> > > >>> > >> >> > > >>> > ``` >> >> > > >>> > (define (print . xs) (for-each display xs) (newline)) >> >> > > >>> > >> >> > > >>> > (define m (make-parameter 0)) >> >> > > >>> > >> >> > > >>> > (define c #f) >> >> > > >>> > >> >> > > >>> > (define (foo) >> >> > > >>> > (parameterize ((m 1)) >> >> > > >>> > (reset >> >> > > >>> > (print 'a: (m)) >> >> > > >>> > (shift k (print 'b: (m)) (set! c k)) >> >> > > >>> > (print 'c: (m))))) >> >> > > >>> > >> >> > > >>> > (define (bar) >> >> > > >>> > (parameterize ((m 2)) >> >> > > >>> > (c #f))) >> >> > > >>> > ``` >> >> > > >>> > >> >> > > >>> > With srfi-226 (using reset/shift as given in the srfi) >> >> > > >>> > reference implementation on Chez, I get this: >> >> > > >>> > >> >> > > >>> > ``` >> >> > > >>> > > (run foo) >> >> > > >>> > a:1 >> >> > > >>> > b:1 >> >> > > >>> > > (run bar) >> >> > > >>> > c:1 >> >> > > >>> > ``` >> >> > > >>> > >> >> > > >>> > With Racket racket/control, I get this: >> >> > > >>> > >> >> > > >>> > ``` >> >> > > >>> > > (foo) >> >> > > >>> > a:1 >> >> > > >>> > b:1 >> >> > > >>> > > (bar) >> >> > > >>> > c:2 >> >> > > >>> > ``` >> >> > > >>> > >> >> > > >>> > I'm switching Gauche's internals to srfi-226 based model, and I >> >> > > >>> > noticed the difference---the current released version of Gauche >> >> > > >>> > (relying on dynamic-wind to handle parameterization) works like >> >> > > >>> > Racket, while the srfi-226 based version (using dynamic env >> >> > > >>> > chain to keep parameters) works like srfi-226 reference >> >> > > >>> > implementation. >> >> > > >>> > >> >> > > >>> > I think srfi-226 behavior is more consistent (when the >> >> > > >>> > delimited continuation is invoked, it restores the dynamic >> >> > > >>> > environment of the continuation of reset), but is there a >> >> > > >>> > plausible explanation of Racket behavior? >> >> > > >>> > >> >> > > >>> > This difference actually caused a compatibility problem of an >> >> > > >>> > existing application so I want to understand it fully. >> >> > > >>> > >> >> > > >>> > >> >> > > >>> > >> >> > > >>> > >> >> > > >>> > >> >> > > >>> > >> >> > > >>> >