Groups 208 of 99+ julia-users › scope using let and local global variables 9 posts by 3 authors Michael Mayo 12 10 14 Hi folks, I have the following code fragment: x 1 let x 2 println x Line 1 exp : x+1 println eval exp Line 2 end It contains two variables both named x, one inside the scope defined by let, and one at global scope. If I run this code the output is: 2 2 This indicates that i that line 1 is using the local version of x, and ii that line 2 is using the global version of x. If I remove this global x I now get an error because eval is looking for the global x which no longer exists: let x 2 println x Line 1 exp : x+1 println eval exp Line 2 end 2 ERROR: x not defined My question: when evaluating an expression using eval such as line 2, how can I force Julia to use the local not global version of x and thus avoid this error? Thanks Mike Jameson 12 11 14 eval, by design, doesn't work that way. there are just too many better alternatives. typically, an anonymous function lambda is the best and most direct replacement: let x 2 println x Line 1 exp - x+1 println exp Line 2 end Michael Mayo 12 11 14 Thanks, but its not quite what I'm looking for. I want to be able to edit the Expr tree and then evaluate different expressions using variables defined in the local scope,not the global scope e.g. for genetic programming, where random changes to an expression are repeatedly evaluated to find the best one . Using anonymous functions could work but modifying the .code property of an anonymous function looks much more complex than modifying the Expr types. Anyway thanks for your answer, maybe your suggestion is the only possible way to achieve this! Mike Jameson 12 11 14 I'm not quite sure what a genetic program of that sort would look like. I would be interested to hear if you get something out of it. Another alternative is to use a module as the environment: module MyEnv end eval MyEnv, : code block This is roughly how the REPL is implemented to work. Mike Innes 12 11 14 You can do this just fine, but you have to be explicit about what variables you want to pass in, e.g. let x 2 exp : x+1 eval : let x $x; $exp; end end If you want to call the expression with multiple inputs, wrap it in a function: let x 2 exp : x+1 f eval : x - $exp f x end Michael Mayo 12 11 14 Thanks for both answers! I figured out a slightly different way of doing it by putting the let assignments into a string with a nothing expression, parsing the string, and then inserting the actual expression to be evaluated into the correct place in the let block: function run assignments,program program_string let for pair in assignments program_string $ program_string $ pair 1 $ pair 2 ; end program_string $ program_string nothing; end program_final parse program_string program_final.args 1 .args end program eval program_final end I can now evaluate the same expression with different inputs in parallel without worrying that they might conflict because all the variables are local, e.g.: pmap dict- run dict,: x+y y , :x 2,:y 5 , :x 6,:y 10 2-element Array Any,1 : 27 106 Thanks for your help! Mike Mike Innes 12 11 14 Great that you got this working, but I strongly recommend working with expression objects here as opposed to strings. It's likely to be more robust and will mean you can use data that isn't parseable i.e. most things other than numbers as inputs. Michael Mayo 12 11 14 Yes you are right! The final version with the strings removed: function run assignments,program program_final Expr :block args Expr for pair in assignments append! args, Expr : , pair 1 , pair 2 end append! args, program program_final.args args eval program_final end Turns out that making a let expression is not required; a simple block expression does the job. Mike Michael Mayo 12 11 14 My apologies, a let block is required otherwise the variables are being defined at global scope. The corrected function: function run assignments,program block Expr :block args Expr for pair in assignments append! args, Expr : , pair 1 , pair 2 end append! args, program block.args args program_final Expr :let, block eval program_final end Mike