From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Mark H Weaver Newsgroups: gmane.lisp.guile.user Subject: Re: Self-evaluating function and closure Date: Sun, 16 Jun 2019 06:09:02 -0400 Message-ID: <87h88p3kpy.fsf@netris.org> References: <20190612202929.GA20126@newvzh.lokolhoz> <87d0je4b82.fsf@netris.org> <20190616090220.GA3181@newvzh.lokolhoz> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="38548"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) To: guile-user@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Sun Jun 16 12:26:16 2019 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hcSMZ-0009sZ-KS for guile-user@m.gmane.org; Sun, 16 Jun 2019 12:26:15 +0200 Original-Received: from localhost ([::1]:38720 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hcSMY-0005VJ-N7 for guile-user@m.gmane.org; Sun, 16 Jun 2019 06:26:14 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:49486) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hcSKm-0004wg-15 for guile-user@gnu.org; Sun, 16 Jun 2019 06:24:26 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hcS86-0008WJ-Jz for guile-user@gnu.org; Sun, 16 Jun 2019 06:11:20 -0400 Original-Received: from world.peace.net ([64.112.178.59]:51166) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hcS86-0008Vt-Fn for guile-user@gnu.org; Sun, 16 Jun 2019 06:11:18 -0400 Original-Received: from mhw by world.peace.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hcS84-0001Dy-UZ; Sun, 16 Jun 2019 06:11:17 -0400 In-Reply-To: <20190616090220.GA3181@newvzh.lokolhoz> (Vladimir Zhbanov's message of "Sun, 16 Jun 2019 12:02:20 +0300") X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 64.112.178.59 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.org gmane.lisp.guile.user:15560 Archived-At: Hi Vladimir, Vladimir Zhbanov writes: > On Sat, Jun 15, 2019 at 08:36:34PM -0400, Mark H Weaver wrote: >> Vladimir Zhbanov writes: >> >> > 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 = #:562:25 ()> >> > scheme@(guile-user)> y >> > $21 = #:562:25 ()> >> > scheme@(guile-user)> (x) >> > $22 = # >> > scheme@(guile-user)> (y) >> > $23 = # >> > 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)? A variable bound within a local lexical environment certainly should not be visible at toplevel. In particular, the transcript that you provided above should *not* result in 'a' being bound in the toplevel environment. When I type those precise commands into Guile 2.2.4 on my system, 'a' is *not* bound at toplevel. Here's what I see: mhw@jojen ~$ guile 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 a () a)) func))) scheme@(guile-user)> (define x (function-generator)) scheme@(guile-user)> (define y (function-generator)) scheme@(guile-user)> x $1 = #:3:26 ()> scheme@(guile-user)> y $2 = #:3:26 ()> scheme@(guile-user)> (x) $3 = # scheme@(guile-user)> (y) $4 = # scheme@(guile-user)> (eq? (x) (y)) $5 = #t scheme@(guile-user)> a ;;; : warning: possibly unbound variable `a' ERROR: In procedure module-lookup: Unbound variable: a Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(guile-user) [1]> >> 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: > > > > 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 = #:108:25 ()> > scheme@(guile-user)> y > $5 = #:108:25 ()> > scheme@(guile-user)> (x) > $6 = # > scheme@(guile-user)> (y) > $7 = # > scheme@(guile-user)> (eq? (x) (y)) > $8 = #t This new transcript does not include an evaluation of 'b' at toplevel. Can you show me a complete transcript that demonstrates this behavior? > scheme@(guile-user)> ,compile (define (function-generator) > (let ((func #f)) > (lambda () (set! func (let b () b)) func))) > Disassembly of 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) ;; # > 6 (box-set! 1 0) > 7 (make-short-immediate 0 2052) ;; # > 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 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) ;; # > 5 (box-set! 1 0) at (unknown file):187:36 > 6 (make-non-immediate 0 54) ;; # > 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) ;; # > 3 (handle-interrupts) > 4 (return-values 2) ;; 1 value > > > Disassembly of 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) ;; # > 16 (return-values 2) ;; 1 value > > > > 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. No, this is the (set! func ...) > 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. I'm sorry about that, but if I understand correctly, it seems that lepton-eda is relying on unspecified behavior here. For better or worse, Scheme behavior is not fully specified in all cases. Comparing procedures for equivalence is one such case. The problem is undecidable in general, so the best we can hope for is an approximation, and we reserve the right to improve that approximation over time. I think it would be a mistake to prohibit such improvements. Regards, Mark