On Sun, Jun 16, 2019 at 07:29:59AM -0400, Mark H Weaver wrote: > Hello again, > > Vladimir Zhbanov <vzhba...@gmail.com> writes: > > > scheme@(guile-user)> (define (function-generator) > > (let ((func #f)) > > (lambda () (set! func (let a () a)) func))) > > [...] > > > - Is there a way to work around this (either using the above 'let' > > construct or anything else)? > > Ideally, the code would be reworked to not expect equivalent procedures > to be distinguishable. However, I should probably offer a hacky but > expedient workaround. Here's one way to make otherwise equivalent > procedures distinguishable: > > Allocate a fresh tag using (list #f), and arrange for the procedure to > return that tag if it's called with a special input that's outside of > the normal domain. Note that for Scheme procedures, the "input" is in > general a list of arguments of arbitrary length. You could use > 'case-lambda', which creates procedures that evaluate different body > expressions depending on how many arguments are passed to it. Just add > a case for an arity that you will never use, which returns the unique > tag. > > In the example you gave, (let a () a) is equivalent to: > > ((letrec ((a (lambda () a))) > a)) > > The procedure returned by (let a () a) expects 0 arguments. It will > raise an error otherwise. We can repurpose the previously erroneous > arity-1 case to return the unique tag, as follows: > > (let ((unique-tag (list #f))) > ((letrec ((a (case-lambda > (() a) > ((x) unique-tag)))) > a))) > > Every time the above expression is evaluated, it will necessarily return > a unique procedure, which, if passed 0 arguments, behaves the same as > the procedure returned by (let a () a). > > Mark >
Great, I've adapted your example to our code and it works nice. Thank you very much! -- Vladimir (λ)επτόν EDA — https://github.com/lepton-eda