I'm a Clojure newbie (many thanks to Rich Hickey and everyone involved
- it's a great programming environment) and I have some trouble with
'eval'.
What I'm trying is:
$ java -cp clojure.jar clojure.lang.Repl
Clojure 1.1.0-alpha-SNAPSHOT
user=> (let [x 1] (eval '(inc x)))
java.lang.Exception: Unable to resolve symbol: x in this context
(NO_SOURCE_FILE:1)
(on a freshly downloaded&compiled clojure from github)
On Thu, Sep 3, 2009 at 8:24 AM, Miron Brezuleanu<mbr...@gmail.com> wrote:
> Hello,
> I'm a Clojure newbie (many thanks to Rich Hickey and everyone involved
> - it's a great programming environment) and I have some trouble with
> 'eval'.
> What I'm trying is:
> $ java -cp clojure.jar clojure.lang.Repl
> Clojure 1.1.0-alpha-SNAPSHOT
> user=> (let [x 1] (eval '(inc x)))
> java.lang.Exception: Unable to resolve symbol: x in this context
> (NO_SOURCE_FILE:1)
> (on a freshly downloaded&compiled clojure from github)
> I'm a Clojure newbie (many thanks to Rich Hickey and everyone involved
> - it's a great programming environment) and I have some trouble with
> 'eval'.
> What I'm trying is:
> $ java -cp clojure.jar clojure.lang.Repl
> Clojure 1.1.0-alpha-SNAPSHOT
> user=> (let [x 1] (eval '(inc x)))
> java.lang.Exception: Unable to resolve symbol: x in this context
> (NO_SOURCE_FILE:1)
> (on a freshly downloaded&compiled clojure from github)
Eval has no access to its lexical environment at runtime; you can only
use global bindings.
The syntax-quote trick Christian showed works because it expands to
something similar to (eval (list 'inc x)), and when eval is called,
the (list 'inc x) is evaluated (as function parameters are), the value
of x in the lexical context is available and the argument to eval
becomes '(inc 2), which works. (nb. eval can evaluate the inc symbol
because it names a global Var.)
I hope I managed to explain this clearly enough. I'm not sure I could
understand this explanation if I didn't already. :)
The critical point here is the environment in which eval evaluates its argument. This is not specified on the documentation page you cite. Eval uses the environment of the current namespace, not taking into account the lexical environment surrounding the call to eval itself. Said differently, the result is the same as if the argument to eval were placed at the outermost expression level of the module inside which eval is called.
Two examples that do work are
1) (eval '(let [x 1] (inc x))) Here the lexical scope is created inside the evaluated expression.
2) (def y 2) (eval '(inc y)) Here the argument to inc is defined in the namespace before eval is called.
> The critical point here is the environment in which eval evaluates its > argument. This is not specified on the documentation page you cite. > Eval uses the environment of the current namespace, not taking into > account the lexical environment surrounding the call to eval itself. > Said differently, the result is the same as if the argument to eval > were placed at the outermost expression level of the module inside > which eval is called.
Turns out my question was asked before, I just used the wrong keywords when searching (local environment instead of local bindings).
I'm interested in eval because I thought it would be nice if we could use something like Python's code.interact() for debugging. Basically, get a repl inside an executing function, that has access to the environment of the function. Poor man's debugger :-)
I guess that is rather hard to obtain, since eval executes in a 'global' context and there is no way to specify an environment in which to execute the code. That could be simulated, if it was a way to reach to the environment of a function (as a map of symbols to values). Then the expression to eval could be bound in a let, something like this:
;; assuming that the local environment is {'a 1 'b 2} ;; and we want to execute (+ a b) ;; we would have to generate something like `(let [a ~(get-local-value 'a) b ~(get-local-value 'b)] (+ a b)
and 'eval' that.
Is there a way to get the list of symbols bound locally and to access their values?
> Is there a way to get the list of symbols bound locally and to access > their values?
I don't think so. Python and Clojure are quite different languages. Python is much more dynamic, with variable lookup happening at runtime. In Clojure, only references to global variables are resolved at runtime. Everything else, in particular lexical environments, are resolved at compile time. Once your code is running, all the local symbols are gone.
There are good and bad aspects to both choices, as so often. Python's dynamic-to-the-end approach facilitates debugging, Clojure's compile- as-much-as-possible attitude yields faster code and better compile- time diagnostics.
> .. Or a better way to simulate code.interact() ?
You would probably have to write a complete Clojure interpreter. Given Clojure's Lisp-ness, that's less of an effort than for other languages, but it's still not a trivial project.
On Thu, Sep 3, 2009 at 4:26 PM, Konrad Hinsen<konrad.hin...@fastmail.net> wrote:
> On 3 Sep 2009, at 14:43, Miron Brezuleanu wrote:
>> Is there a way to get the list of symbols bound locally and to access >> their values?
> I don't think so. Python and Clojure are quite different languages. > Python is much more dynamic, with variable lookup happening at > runtime. In Clojure, only references to global variables are resolved > at runtime. Everything else, in particular lexical environments, are > resolved at compile time. Once your code is running, all the local > symbols are gone.
I was afraid of that (the fact that eval didn't have an 'env' argument as in more Scheme-like languages was hinting to the fact that access to the environment is not easy after compilation).
> There are good and bad aspects to both choices, as so often. Python's > dynamic-to-the-end approach facilitates debugging, Clojure's compile- > as-much-as-possible attitude yields faster code and better compile- > time diagnostics.
>> .. Or a better way to simulate code.interact() ?
> You would probably have to write a complete Clojure interpreter. Given > Clojure's Lisp-ness, that's less of an effort than for other > languages, but it's still not a trivial project.
Well, I don't need a debugger _that_ much. :-) I was just trying to make sure I don't end up not using a code.interact() equivalent because I missed some Clojure API.
I am not familiar with the Python code.interact() thing and what it
does so I may be missing something but if you are looking to do
debugging is there a reason you can't use a Java debugger to debug
your Clojure code? (I have heard some people have had success for
JSwat.) I guess that is not the same as having a REPL.
Cheers,
James
On Sep 3, 11:47 pm, Miron Brezuleanu <mbr...@gmail.com> wrote:
> On Thu, Sep 3, 2009 at 4:26 PM, Konrad Hinsen<konrad.hin...@fastmail.net> wrote:
> > On 3 Sep 2009, at 14:43, Miron Brezuleanu wrote:
> >> Is there a way to get the list of symbols bound locally and to access
> >> their values?
> > I don't think so. Python and Clojure are quite different languages.
> > Python is much more dynamic, with variable lookup happening at
> > runtime. In Clojure, only references to global variables are resolved
> > at runtime. Everything else, in particular lexical environments, are
> > resolved at compile time. Once your code is running, all the local
> > symbols are gone.
> I was afraid of that (the fact that eval didn't have an 'env' argument
> as in more Scheme-like languages was hinting to the fact that access
> to the environment is not easy after compilation).
> > There are good and bad aspects to both choices, as so often. Python's
> > dynamic-to-the-end approach facilitates debugging, Clojure's compile-
> > as-much-as-possible attitude yields faster code and better compile-
> > time diagnostics.
> >> .. Or a better way to simulate code.interact() ?
> > You would probably have to write a complete Clojure interpreter. Given
> > Clojure's Lisp-ness, that's less of an effort than for other
> > languages, but it's still not a trivial project.
> Well, I don't need a debugger _that_ much. :-) I was just trying to
> make sure I don't end up not using a code.interact() equivalent
> because I missed some Clojure API.
On Fri, Sep 4, 2009 at 4:01 AM, James Sofra<james.so...@gmail.com> wrote:
> Hi,
> I am not familiar with the Python code.interact() thing and what it > does so I may be missing something but if you are looking to do > debugging is there a reason you can't use a Java debugger to debug > your Clojure code? (I have heard some people have had success for > JSwat.) I guess that is not the same as having a REPL.
A basic code.interact sample (the >>> used by Python as prompt may look like email quotations in some clients): IDLE 1.2.4
>>> import code >>> def testCodeInteract():
a = 1 b = 2 code.interact("Test Code Interact", raw_input, locals())
>>> a <--- this is the IDLE repl
Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> a NameError: name 'a' is not defined
>>> testCodeInteract() Test Code Interact >>> a <--- this is the 'inner' code.interact() repl, 'a' is bound here 1 >>> a + b 3 >>> <--- pressed Ctrl-D to exit the inner repl >>> <--- outer repl again
I'll take a look at JSwat, even though I'm quite comfortable with a REPL in Emacs to test small pieces of code (plus automated tests later) and 'printf debugging' - the problem is they are sometimes not enough at the worst moments, so a more capable debugger would come in handy.
> On Sep 3, 9:26 am, Konrad Hinsen <konrad.hin...@fastmail.net> wrote: >> I don't think so. Python and Clojure are quite different languages. >> Python is much more dynamic, with variable lookup happening at >> runtime.
> Or, more simply, Python is an interpreter, Clojure is a compiler. So > Clojure's "eval" actually compiles the form into Java bytecode, then > executes it.
I'm not sure this is an interpreter/compiler issue :-) I think it is more of a resource allocation problem, i.e. what features to add to Clojure and when.
The code.interact() trick is not specific to Python (or interpreted languages). I guess it would be implementable in Schemes that provide the environment as an argument to eval, and some of them are compiled. Smalltalk also has this, and there is the "Immediate Window" in Visual Studio which provides a C# REPL at any point on the callstack after hitting a breakpoint (similar to the Smalltalk debugger). I'm not familiar with the details of the "Immediate Window" implementation, I assume they make good use of debugging information.
Anyway, Clojure is great even without this feature - maybe it will be added at some point in the future. I sure don't mind the extra speed gained from compiling as much as possible :-)
> Or, more simply, Python is an interpreter, Clojure is a compiler. So > Clojure's "eval" actually compiles the form into Java bytecode, then > executes it.
I'd say both Python and Clojure are somewhere in between the classical extremes of "interpreter" and "compiler". The extreme cases are the easiest to understand, but newcomers to both Python and Clojure often have a hard time to figure out what exactly happens when and what the consequences are. Perhaps tutorials should address this issue more clearly.
On Sep 4, 1:55 am, Miron Brezuleanu <mbr...@gmail.com> wrote:
> I'm not sure this is an interpreter/compiler issue :-) I think it is
> more of a resource allocation problem, i.e. what features to add to
> Clojure and when.
True, it's that Clojure does not have first-class environments, either
dynamic or lexical. I think it's been discussed, but not very
seriously.