On Thu, Oct 1, 2009 at 12:03 PM, jon <superuser...@googlemail.com> wrote: > > On Sep 29, 10:31 pm, Rich Hickey <richhic...@gmail.com> wrote: >> On Tue, Sep 29, 2009 at 4:04 PM, jon <superuser...@googlemail.com> wrote: >> >> Before leaping to implementation/performance issues, I think it is >> important to think about the semantics of this - what does it mean? I >> think you will get a lot of confusion, given: >> >> (defn foo [] >> (send-off-something-that-uses-env (fn [] ... (use-env)))) >> >> (defn bar [] >> (establish-env env >> (foo))) >> >> If fns 'capture' these environments when created, and re-establish >> them when called, then foo itself will have captured the environment >> at *its* definition/creation point, and will re-establish that, thus >> the environment setup by bar will not be conveyed through foo to >> something-that-uses-env - *but*, if you substituted the body of foo >> for its call, it would. That's bad. > > Hi Rich, > > (Note - when I say 'environment' below I'm referring to one specially > designated 'environment Var', not the whole set of dynamically bound > Vars we are used to.) > > I'm not sure whether you are taking into account the fact that the > semantics of my proposal are that each (fn ..) will only capture (and > later rebind) the environment if it is non-nil at the point it is > instantiated (in the java sense). The environment's root-binding is > nil, and all the user's code should be loaded in this state so that > the (defn ..)s themselves don't capture anything.. ie.no capturing > happens until the user code explicitly 'switches it on' with a (with- > env ..) and then only newly instantiated (fn ..)s will capture the > current environment. > > For those kinds of environment data that don't require the fully > dynamic behavior of the regular Vars, wouldn't this be more intuitive > default behavior (ie.that all code "kicked-off" under a given > environment should be evaluated under that environment, even if that > happens later on) rather than the current situation in which any > eagerly evaluated code would see the current environment, and any > delayed-evaluation code would see 'whatever it happens to be at the > time', which would be harder to control? > For the (presumably rare) case that some library code (which may be > called under a non-nil environment) needs to create a (fn ..utilizing > *env*..) which is to be passed out and executed under some yet-to-be- > determined environment.. it could simply be wrapped like this: > (with-env nil (fn ..utilizing *env*..)) > > ----- > The example you gave doesn't behave badly (ie.differently) when > replacing the body of foo for its call.. as demonstrated below. > > user=> (defn send-off-something-that-uses-env [f] (+ 100 (f))) > #'user/send-off-something-that-uses-env > user=> (defn foo [] (send-off-something-that-uses-env (fn [] (+ 10 > *env*)))) > #'user/foo > user=> (defn bar [] (with-env 1 (foo))) > #'user/bar > user=> (bar) > 111 > user=> (defn bar [] (with-env 1 (send-off-something-that-uses-env (fn > [] (+ 10 *env*))))) > #'user/bar > user=> (bar) > 111 > > Could you elaborate a bit more on the bad behavior you see..?
It simply doesn't compose or flow. Making the nil env special (e.g. non-replacing) just moves the problem into higher-order functions that use the construct: (defn needs-x [] (use-env-x)) (defn needs-y [] (use-env-y)) (defn foo [] (with-env x (fn [f] (needs-x) (f)))) (let [f (foo)] (with-env y (f needs-y))) needs-y isn't going to get it. Rich --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---