guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Self-evaluating function and closure


From: Vladimir Zhbanov
Subject: Re: Self-evaluating function and closure
Date: Sun, 16 Jun 2019 12:02:20 +0300
User-agent: Mutt/1.10.1 (2018-07-13)

Mark,

On Sat, Jun 15, 2019 at 08:36:34PM -0400, Mark H Weaver wrote:
> Hi Vladimir,
> 
> Vladimir Zhbanov <address@hidden> 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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]