What's the best practice for forcing (lambda () ..) to generate a unique closure object always?
*(let loop () (define x (lambda () 'myvalue)) (print x "\n") (loop))* #<procedure #2 x> #<procedure #3 x> #<procedure #4 x> #<procedure #5 x> [...] *[ctrl+c],q*
Dear Marc, How can I make Gambit always generate unique closure objects for (lambda () ...) ? A (declare) to enforce this would do the job. I'm having a table with test: eq? where the key is a closure and thus needs to guaranteedly be unique. This should be a perfectly valid usecase. I noted that currently in compiled code (lambda () ...) not guaranteedly returns a unique closure object in certain circumstances: if a closure closes over no variables, or Gambit optimizes away all closed over variables so no variables are closed over that way, then it does not generate a unique closure. This was quite surprising to me as my best understanding of R5RS spec (here& here) is that eq? should work on procedures: "Each procedure created as the result of evaluating a lambda expression is (conceptually) tagged with a storage location, in order to make eqv? and eq? work on procedures (see section 6.1)." Perhaps the wording could have been even more precise. I acknowledge this Gambit optimization is really useful many times. Though there should be a way to disable it as it wouldn't be a reliable coding strategy to need to outsmart the optimizer for correct function. Thanks! Mikael Example: $ *gsc* Gambit v4.6.6 * * $ *echo **(let loop () (define x (lambda () 'myvalue)) (print x "\n") (loop)) > test.scm* $ *gsc* Gambit v4.6.6
*(compile-file "test.scm")* "test.o1" *(load "test.o1")* #<procedure #2> #<procedure #2> #<procedure #2> #<procedure #2> #<procedure #2> #<procedure #2> #<procedure #2> [...]
This (let loop ((v 0)) (define x (lambda () *v* 'myvalue)) (print x "\n") (loop 1)) gives the same behavior. Note that the lambda closes over v, though the compiler optimizes it away. Neither (let loop ((v 0)) (define x (lambda (z) (declare (not optimize-dead-local-variables)) v 'myvalue)) (print x "\n") (loop 1)) works, which may appear a bit surprising! Here's a hack around the optimizer though: (let loop ((v 0)) (define x (lambda (z) (case z ((never-happens) v) (else 'myvalue)))) (print x "\n") (loop 1))
Afficher les réponses par date
participants (1)
-
Mikael