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 On Friday, December 12, 2014 11:43:54 AM UTC+13, Michael Mayo wrote: > > 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 > > On Friday, December 12, 2014 11:07:42 AM UTC+13, Mike Innes wrote: >> >> 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. >> >> On 11 December 2014 at 21:40, Michael Mayo <mm...@waikato.ac.nz> wrote: >> >>> 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 >>> >>> >>> >>> On Thursday, December 11, 2014 10:34:22 PM UTC+13, Mike Innes wrote: >>>> >>>> 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 >>>> >>>> >>>> On 11 December 2014 at 06:32, Jameson Nash <vtj...@gmail.com> wrote: >>>> >>>>> 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. >>>>> >>>>> On Thu Dec 11 2014 at 1:26:57 AM Michael Mayo <mm...@waikato.ac.nz> >>>>> wrote: >>>>> >>>>>> 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 >>>>>> >>>>>> >>>>>> On Thursday, December 11, 2014 6:56:15 PM UTC+13, Jameson wrote: >>>>>> >>>>>>> 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 >>>>>>> >>>>>>> >>>>>>> On Wed Dec 10 2014 at 10:43:00 PM Michael Mayo <mm...@waikato.ac.nz> >>>>>>> wrote: >>>>>>> >>>>>>>> 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 >>>>>>>> >>>>>>> >>>> >>