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.

Reply via email to