Re: [Chicken-users] continuation example: different behavior from other Scheme implementations

2019-10-19 Thread Ricardo Gabriel Herdt



Am 19.10.2019 18:57 schrieb felix.winkelm...@bevuta.com:

But what I forgot, and which may be the confusing part is that
after the mapping is complete, "numbers" (in your example) will be
assigned once again - the continuation includes everything following
the invocation of "map". Only the REPL "cuts off" this continuation
(otherwise you would have an infinite loop, similar to when you would
run your example code as a non-interactive program).


Thanks again, this makes sense, I had already experienced this infinite 
loop when using a compiled version of the program.


I added a note to the wiki mentioned 
(https://en.wikibooks.org/wiki/Scheme_Programming/Continuations) telling 
to be aware of implementation-dependent behavior, just in case someone 
stumbles on this issue in the future.


Cheers,

Ricardo

___
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users


Re: [Chicken-users] continuation example: different behavior from other Scheme implementations

2019-10-19 Thread felix . winkelmann
> I found this in R5RS/R7RS/SRFI-1: "The dynamic order in which proc is 
> applied to the elements of the lists is unspecified". Indeed redefining 
> map in all implementations as
> 
> (define (map f l)
>(cond ((null? l) '())
> (else (cons (f (car l))
>  (map f (cdr l))
> 
> make all behave the same way (I know this is not a complete map 
> implementation, is just an example).

Exactly. In CHICKEN, "map" is implemented in a (nearly) canonical
way (modulo some edge cases for extra arguments, etc.). On interpreted
implementations, "map" may be implemented in a lower-level way,
perhaps mutating the result list while it is build. Continuations expose
such details in a sometimes surprising way.

> 
> R7RS adds this: "If multiple returns occur from map, the values returned 
> by earlier returns are not mutated". Does this mean returns through 
> continuation calls?

That's correct.

> 
> I was curious how CHICKEN implements map and found the following in 
> library.scm:
> 
> (define (##sys#map p lst0)
>(let loop ((lst lst0))
>  (cond ((eq? lst '()) lst)
>((pair? lst)
>  (cons (p (##sys#slot lst 0)) (loop (##sys#slot lst 1))) )
>(else (##sys#error-not-a-proper-list lst0 'map)) ) ))
> 

> So still I don't get why calling any stored continuation appends the 
> result to the previously computed "numbers", but if the standard allows 
> this behavior it's not a big deal.

As you save the continuation, you effectively retain all local state
from executions before the continuation was captured. The result list
is constructed recursively, the 2nd return from "p" above will restart
the mapping of 6 elements (with element 1 replaced by 76) until the list
runs out. What is done before is thus returned once again, with extra
elements appended, since you restart the processing of the list, you sort
of jump back in time into the recursion, effectively prolonging it. 

But what I forgot, and which may be the confusing part is that
after the mapping is complete, "numbers" (in your example) will be
assigned once again - the continuation includes everything following 
the invocation of "map". Only the REPL "cuts off" this continuation
(otherwise you would have an infinite loop, similar to when you would
run your example code as a non-interactive program).


felix


___
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users


Re: [Chicken-users] continuation example: different behavior from other Scheme implementations

2019-10-19 Thread Ricardo Gabriel Herdt

Am 19.10.2019 15:46 schrieb megane:

There's special compiler syntax for map; search for 'map-loop in the
sources. You can also see what your code expands to by giving -debug 2
flag to csc.


Thanks megane,

with -debug 2 I see that map uses some local variables that are changed 
with set! in the loop, so it's quite more complex than I thought, and 
this explains the behavior seen. Thanks for the hints.


;; generated code
(set! numbers
  (let ((g2836 (scheme#cons (##core#undefined) '(
(let ((g2737 g2836) (g2938 capture-from-map) (g3539 '(1 2 3 4 5 6)))
  (let ((t46 (##sys#check-list g3539 'map)))
(##core#app
  (let ((map-loop2340 (##core#undefined)))
(let ((t45 (set! map-loop2340
 (##core#lambda
   (g3541)
   (if (scheme#pair? g3541)
 (let ((g2442 (scheme#cons (g2938 
(##sys#slot g3541 '0)) '(
   (let ((t43 (##sys#setslot g2836 '1 
g2442)))

 (let ((t44 (set! g2836 g2442)))
   (##core#app map-loop2340 (##sys#slot 
g3541 '1)

 (##sys#slot g2737 '1))
  (let () map-loop2340)))
  g3539)

Regards,

Ricardo



___
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users


Re: [Chicken-users] continuation example: different behavior from other Scheme implementations

2019-10-19 Thread megane

Ricardo Gabriel Herdt  writes:

> Am 19.10.2019 14:18 schrieb felix.winkelm...@bevuta.com:
>> The exact behaviour of re-
>> entering a continuation captured during execution of "map" is, I think,
>> dependent on implementation details (there may be a note about this in 
>> the
>> SRFI-1 document or R7RS, I can't remember right now).
>
> Many thanks for the fast and detailed answer.
>
> I found this in R5RS/R7RS/SRFI-1: "The dynamic order in which proc is 
> applied to the elements of the lists is unspecified". Indeed redefining 
> map in all implementations as
>
> (define (map f l)
>(cond ((null? l) '())
> (else (cons (f (car l))
>  (map f (cdr l))
>
> make all behave the same way (I know this is not a complete map 
> implementation, is just an example).
>
> R7RS adds this: "If multiple returns occur from map, the values returned 
> by earlier returns are not mutated". Does this mean returns through 
> continuation calls?

That's how I understand it.

>
> I was curious how CHICKEN implements map and found the following in 
> library.scm:
>
> (define (##sys#map p lst0)
>(let loop ((lst lst0))
>  (cond ((eq? lst '()) lst)
>((pair? lst)
> (cons (p (##sys#slot lst 0)) (loop (##sys#slot lst 1))) )
>(else (##sys#error-not-a-proper-list lst0 'map)) ) ))
>
> ...
> (set! scheme#map
>  (lambda (fn lst1 . lsts)
>(if (null? lsts)
>(##sys#map fn lst1)
>(let loop ((all (cons lst1 lsts)))
>  (let ((first (##sys#slot all 0)))
>(cond ((pair? first)
>   (cons (apply fn (mapsafe (lambda (x) (car x)) all #t 'map))
>  (loop (mapsafe (lambda (x) (cdr x)) all #t 'map)) ) )
>  (else (check (##core#inline "C_i_cdr" all) #t 'map)
> '() ) ) ) ) ) ) )
> ...
>
> So still I don't get why calling any stored continuation appends the 
> result to the previously computed "numbers", but if the standard allows 
> this behavior it's not a big deal.

There's special compiler syntax for map; search for 'map-loop in the
sources. You can also see what your code expands to by giving -debug 2
flag to csc.

>
> Regards,
>
> Ricardo
>
>
> ___
> Chicken-users mailing list
> Chicken-users@nongnu.org
> https://lists.nongnu.org/mailman/listinfo/chicken-users


___
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users


Re: [Chicken-users] continuation example: different behavior from other Scheme implementations

2019-10-19 Thread Ricardo Gabriel Herdt

Am 19.10.2019 14:18 schrieb felix.winkelm...@bevuta.com:

The exact behaviour of re-
entering a continuation captured during execution of "map" is, I think,
dependent on implementation details (there may be a note about this in 
the

SRFI-1 document or R7RS, I can't remember right now).


Many thanks for the fast and detailed answer.

I found this in R5RS/R7RS/SRFI-1: "The dynamic order in which proc is 
applied to the elements of the lists is unspecified". Indeed redefining 
map in all implementations as


(define (map f l)
  (cond ((null? l) '())
(else (cons (f (car l))
(map f (cdr l))

make all behave the same way (I know this is not a complete map 
implementation, is just an example).


R7RS adds this: "If multiple returns occur from map, the values returned 
by earlier returns are not mutated". Does this mean returns through 
continuation calls?


I was curious how CHICKEN implements map and found the following in 
library.scm:


(define (##sys#map p lst0)
  (let loop ((lst lst0))
(cond ((eq? lst '()) lst)
  ((pair? lst)
   (cons (p (##sys#slot lst 0)) (loop (##sys#slot lst 1))) )
  (else (##sys#error-not-a-proper-list lst0 'map)) ) ))

...
(set! scheme#map
(lambda (fn lst1 . lsts)
  (if (null? lsts)
  (##sys#map fn lst1)
  (let loop ((all (cons lst1 lsts)))
(let ((first (##sys#slot all 0)))
  (cond ((pair? first)
 (cons (apply fn (mapsafe (lambda (x) (car x)) all #t 'map))
   (loop (mapsafe (lambda (x) (cdr x)) all #t 'map)) ) )
(else (check (##core#inline "C_i_cdr" all) #t 'map)
  '() ) ) ) ) ) ) )
...

So still I don't get why calling any stored continuation appends the 
result to the previously computed "numbers", but if the standard allows 
this behavior it's not a big deal.


Regards,

Ricardo


___
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users


Re: [Chicken-users] continuation example: different behavior from other Scheme implementations

2019-10-19 Thread felix . winkelmann
> Could someone please explain what's going on? Why would Chicken append 
> the new list to the old value of 'numbers', which as I understand should 
> be empty at the moment of the stored continuation?

You are re-entering the execution of "map" by calling the stored
continuation, which was at that point of time in the process of
producing a list, and thus is entered again, producing yet another
list of six values (since that is the state of the world captured in
the first element of "continuations". The exact behaviour of re-
entering a continuation captured during execution of "map" is, I think, 
dependent on implementation details (there may be a note about this in the
SRFI-1 document or R7RS, I can't remember right now).

Note also that the "old value of numbers" that you speak of above
is the value of a global variable, which will not be part of the continuation.
It's the computation that produces the result that you re-enter. 

I hope this is somewhat understandable, apologies if I failed to make it so.


felix


___
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users


[Chicken-users] continuation example: different behavior from other Scheme implementations

2019-10-19 Thread Ricardo Gabriel Herdt

Hi all,

I'm trying to understand how continuations work, and tried out the first 
example described at 
"https://en.wikibooks.org/wiki/Scheme_Programming/Continuations; with 
Chicken (5.1):


---
(define continuations '())

(define (push arg)
  (set! continuations
(cons arg continuations)))

(define (capture-from-map arg)
  (call-with-current-continuation
   (lambda (cc)
 (push cc)
 arg)))

(define numbers (map capture-from-map '(1 2 3 4 5 6)))

;;REPL

numbers

(1 2 3 4 5 6)

((car (reverse continuations)) 76)

((result "#") (output . ""))

numbers

(1 2 3 4 5 6 76 2 3 4 5 6)
---

To my surprise, this last value stored at 'numbers' differs from other 
implementations (and from the example described on the Wiki):

Guile/Racket/MIT: (76 2 3 4 5 6)
Chez: (1 2 3 4 76 6)

Could someone please explain what's going on? Why would Chicken append 
the new list to the old value of 'numbers', which as I understand should 
be empty at the moment of the stored continuation?


Regards,

Ricardo


___
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users