On Tue, Aug 9, 2016 at 2:35 PM, Ben Greenman <[email protected]> wrote:
> Here's something in the ballpark. > > #lang racket > > (define-namespace-anchor nsa) > (define ns (namespace-anchor->namespace nsa)) > > (let ((xyz 1)) > (for ((name '(x y z))) > (namespace-set-variable-value! name (lambda () (displayln (format > "~a: ~a" name xyz)) (set! xyz (add1 xyz))) #f ns))) > > (eval '(x) ns) > > This doesn't actually create a top-level binding, though. I can't say (x) and have it work. (Incidentally, is 'top-level binding' the right term here?) > On Tue, Aug 9, 2016 at 5:20 PM, 'John Clements' via Racket Users < > [email protected]> wrote: > >> >> > On Aug 9, 2016, at 4:46 PM, David Storrs <[email protected]> >> wrote: >> > >> > In Perl it's possible to generate main-namespace functions like so: >> > >> > perl -E 'my $z = 1; for (qw/foo bar baz/) {my $x = $_; *$_ = sub{ say >> "$x: ", $z++ }}; foo(); bar(); baz();' >> > >> > This outputs: >> > foo: 1 >> > bar: 2 >> > baz: 3 >> > >> > >> > Note that it is generating top-level subroutines that can be called >> from elsewhere in the program (including other modules) and that those >> subroutines close over existing lexical variables. >> > >> > >> > I tried to do this in Racket and haven't been able to figure it out: >> > >> > First attempt, only partial solution: >> > $ racket >> > -> (for ((name '(x y z))) (define name (lambda () (displayln "foo")))) >> > >> > ; /Applications/Racket_v6.3/collects/racket/private/for.rkt:1487:62: >> begin >> > ; (possibly implicit): no expression after a sequence of internal >> definitions >> > ; in: (begin (define name (lambda () (displayln "foo")))) >> > ; [,bt for context] >> > >> > >> > I found 'eval', but that doesn't close over lexical variables ( >> https://docs.racket-lang.org/guide/eval.html: "The eval function cannot >> see local bindings"): >> > >> > $ racket >> > Welcome to Racket v6.3. >> > -> (let ((xyz 1)) (for ((name '(x y z))) (eval `(define ,name (lambda >> () (displayln (format "~a: ~a" ,name ,xyz) (set! xyz (add1 xyz)))))))) >> > >> > -> (x) >> > (x) >> > ; xyz: undefined; >> > ; cannot reference undefined identifier >> > ; [,bt for context] >> > >> > >> > What have I not found? >> >> Racket is essentially a lexically scoped language. That is: it should be >> possible to look at a piece of code and figure out where the binding for a >> given variable is. It does have a dynamic binding mechanism, but the names >> that are bound dynamically … can be determined lexically. >> >> This might seem to prevent the kind of code that you’re talking about, >> but Racket compensates for this with an extraordinarily flexible macro >> system, and a very permissive notion of what exactly constitutes >> “compile-time.” It’s certainly possible to dynamically generate a piece of >> code using macros. Once generated, though, this piece of code is going to >> behave dependably. >> >> How does this affect your particular example? Well, it’s extremely easy >> to write a macro that does what you describe: >> >> #lang racket >> >> (define-syntax makefuns >> (syntax-rules () >> [(_ name ...) >> (begin (define name (lambda () (displayln "foo"))) >> ...)])) >> >> (makefuns x y z) >> >> (x) >> >> (y) >> >> (z) >> >> >> >> Does this solve your problem? If not, why not? It’s going to depend a lot >> on what exactly you want to do. >> >> >> Hope this helps, apologies for telling you anything that you already knew. >> >> John >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "Racket Users" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> For more options, visit https://groups.google.com/d/optout. >> > > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.

