Mark, On Sat, Jun 15, 2019 at 08:36:34PM -0400, Mark H Weaver wrote: > Hi Vladimir, > > Vladimir Zhbanov <vzhba...@gmail.com> writes: > > > Greetings, > > > > I have tried almost a textbook example with Guile 2.2.4: > > > > scheme@(guile-user)> (define (function-generator) > > (let ((func #f)) > > (lambda () (set! func (let a () a)) func))) > > > > scheme@(guile-user)> (define x (function-generator)) > > scheme@(guile-user)> (define y (function-generator)) > > scheme@(guile-user)> x > > $20 = #<procedure f9f9d0 at <unknown port>:562:25 ()> > > scheme@(guile-user)> y > > $21 = #<procedure bf2660 at <unknown port>:562:25 ()> > > scheme@(guile-user)> (x) > > $22 = #<procedure a ()> > > scheme@(guile-user)> (y) > > $23 = #<procedure a ()> > > scheme@(guile-user)> (eq? (x) (y)) > > $24 = #t > > > > The result is unexpected for me, I expected a new self-evaluating > > procedure every time I run the function-generator procedure (and > > it works differently with Guile 2.0, IIUC, cannot check just now). > > Why would you expect 'eq?' to return #false here? Do you know of any > text in Guile's manual, or in any of the relevant Scheme standards, that > would lead you to expect this? > > Since (let a () a) contains no free variable references, every procedure > returned by (let a () a) is operationally equivalent to every other > procedure returned by it. Therefore, as I understand it, a conforming > Scheme implementation is permitted (but not required) to return the same > procedure object every time.
If the procedure is defined inside a closure, should it be available at toplevel (especially with the same name it was defined inside a function)? > > I just refreshed my memory of the requirements of the R5RS, R6RS, and > R7RS on 'eq?' when applied to procedures. Conforming implementations > are required to return #true if the procedures have the same "location > tags", and are required to return #false if the procedures would behave > differently (return different value(s) or have different side effects) > for some arguments. > > > AFAICS, Guile creates a toplevel procedure "a" while it should not do > >so. > > > > scheme@(guile-user)> a > > $25 = #<procedure 109aa90 at <unknown port>:422:25 ()> > > If this were the case, it would certainly be a bug. However, I cannot > reproduce it, and I strongly suspect that you had defined 'a' as a > toplevel variable earlier in your Guile session and forgot about it. No, I'haven't defined anything before. OK, let's start with a fresh session and use another name: <Geiser session starts here> GNU Guile 2.2.4 Copyright (C) 1995-2017 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> (define (function-generator) (let ((func #f)) (lambda () (set! func (let b () b)) func))) scheme@(guile-user)> (define x (function-generator)) scheme@(guile-user)> (define y (function-generator)) scheme@(guile-user)> x $4 = #<procedure 16949b0 at <unknown port>:108:25 ()> scheme@(guile-user)> y $5 = #<procedure 1860200 at <unknown port>:108:25 ()> scheme@(guile-user)> (x) $6 = #<procedure b ()> scheme@(guile-user)> (y) $7 = #<procedure b ()> scheme@(guile-user)> (eq? (x) (y)) $8 = #t scheme@(guile-user)> ,compile (define (function-generator) (let ((func #f)) (lambda () (set! func (let b () b)) func))) Disassembly of <unnamed function> at #x98: 0 (assert-nargs-ee/locals 1 1) ;; 2 slots (0 args) at (unknown file):185:9 1 (static-ref 1 75) ;; function-generator 3 (define! 1 1) 4 (make-non-immediate 0 74) ;; #<procedure function-generator ()> 6 (box-set! 1 0) 7 (make-short-immediate 0 2052) ;; #<unspecified> 8 (handle-interrupts) 9 (return-values 2) ;; 1 value Disassembly of function-generator at #xc0: 0 (assert-nargs-ee/locals 1 1) ;; 2 slots (0 args) at (unknown file):185:9 1 (make-short-immediate 1 4) ;; #f 2 (box 1 1) 3 (make-closure 0 7 1) ;; anonymous procedure at #xb2c0aac8 (1 free var) at (unknown file):187:25 6 (free-set! 0 1 0) ;; free var 0 8 (handle-interrupts) 9 (return-values 2) ;; 1 value Disassembly of <unnamed function> at #xe8: 0 (assert-nargs-ee/locals 1 1) ;; 2 slots (0 args) at (unknown file):187:25 1 (free-ref 1 1 0) ;; free var 0 3 (make-non-immediate 0 57) ;; #<procedure b ()> 5 (box-set! 1 0) at (unknown file):187:36 6 (make-non-immediate 0 54) ;; #<procedure b ()> 8 (handle-interrupts) 9 (return-values 2) ;; 1 value Disassembly of b at #x110: 0 (assert-nargs-ee/locals 1 1) ;; 2 slots (0 args) at (unknown file):187:47 1 (make-non-immediate 0 49) ;; #<procedure b ()> 3 (handle-interrupts) 4 (return-values 2) ;; 1 value Disassembly of <unnamed function> at #x124: 0 (assert-nargs-ee/locals 1 1) ;; 2 slots (0 args) at (unknown file):187:47 1 (static-patch! 37 16) 4 (make-non-immediate 1 33) ;; "function-generator" 6 (string->symbol 1 1) 7 (static-set! 1 34) ;; function-generator 9 (static-patch! 35 -34) 12 (static-patch! 34 -17) 15 (make-short-immediate 0 2052) ;; #<unspecified> 16 (return-values 2) ;; 1 value <Geiser session ends here> The same behaviour, though now the procedure name is 'b'. The line that confuses me here is: 5 (box-set! 1 0) at (unknown file):187:36 I suspect this is a toplevel definition. To make it clear, why I ask here, this new behaviour in Guile 2.2 broke our schematic frontend actions (that were defined in such a way I presented above) after moving from Guile 2.0 to it. IIUC, at least guile versions compiled on Debian and FreeBSD involved. -- Vladimir (λ)επτόν EDA — https://github.com/lepton-eda