使用局部变量评估表达式 [英] Evaluate expression with local variables
问题描述
我正在编写一个遗传程序,以测试随机生成的表达式的适用性.这里显示的是生成表达式的函数以及主要函数. DIV和GT在代码的其他地方定义:
I'm writing a genetic program in order to test the fitness of randomly generated expressions. Shown here is the function to generate the expression as well a the main function. DIV and GT are defined elsewhere in the code:
function create_single_full_tree(depth, fs, ts)
"""
Creates a single AST with full depth
Inputs
depth Current depth of tree. Initially called from main() with max depth
fs Function Set - Array of allowed functions
ts Terminal Set - Array of allowed terminal values
Output
Full AST of typeof()==Expr
"""
# If we are at the bottom
if depth == 1
# End of tree, return function with two terminal nodes
return Expr(:call, fs[rand(1:length(fs))], ts[rand(1:length(ts))], ts[rand(1:length(ts))])
else
# Not end of expression, recurively go back through and create functions for each new node
return Expr(:call, fs[rand(1:length(fs))], create_single_full_tree(depth-1, fs, ts), create_single_full_tree(depth-1, fs, ts))
end
end
function main()
"""
Main function
"""
# Define functional and terminal sets
fs = [:+, :-, :DIV, :GT]
ts = [:x, :v, -1]
# Create the tree
ast = create_single_full_tree(4, fs, ts)
#println(typeof(ast))
#println(ast)
#println(dump(ast))
x = 1
v = 1
eval(ast) # Error out unless x and v are globals
end
main()
我正在基于某些允许的函数和变量生成一个随机表达式.从代码中可以看出,表达式只能包含符号x和v,以及值-1.我将需要使用各种x和v值来测试表达式;这里我只是使用x = 1和v = 1来测试代码.
I am generating a random expression based on certain allowed functions and variables. As seen in the code, the expression can only have symbols x and v, as well as the value -1. I will need to test the expression with a variety of x and v values; here I am just using x=1 and v=1 to test the code.
该表达式已正确返回,但是,eval()仅可与全局变量一起使用,因此除非我声明x和v为全局变量,否则它将在运行时出错(错误:LoadError:UndefVarError:x未定义) .如果可能,我想避免使用全局变量.有没有更好的方法可以使用局部定义的变量来生成和评估这些生成的表达式?
The expression is being returned correctly, however, eval() can only be used with global variables, so it will error out when run unless I declare x and v to be global (ERROR: LoadError: UndefVarError: x not defined). I would like to avoid globals if possible. Is there a better way to generate and evaluate these generated expressions with locally defined variables?
推荐答案
在元编程是Julia文档的一部分,在 eval()
和效果部分下有一句话说
In the Metaprogramming part of the Julia documentation, there is a sentence under the eval()
and effects section which says
每个
module
都有其自己的eval()
函数,该函数在其全局范围内评估表达式.
Every
module
has its owneval()
function that evaluates expressions in its global scope.
类似地,REPL帮助?eval
将在Julia 0.6.2上为您提供以下帮助:
Similarly, the REPL help ?eval
will give you, on Julia 0.6.2, the following help:
计算给定模块中的表达式并返回结果.每个
Module
(用baremodule
定义的除外)都有其自己的eval
一参数定义,该定义对模块中的表达式求值.
Evaluate an expression in the given module and return the result. Every
Module
(except those defined withbaremodule
) has its own 1-argument definition ofeval
, which evaluates expressions in that module.
我假设您在示例中的Main
模块中工作.这就是为什么需要在此处定义全局变量的原因.对于您的问题,可以使用macro
s并直接在宏内部插入x
和y
的值.
I assume, you are working in the Main
module in your example. That's why you need to have the globals defined there. For your problem, you can use macro
s and interpolate the values of x
and y
directly inside the macro.
一个最小的工作示例是:
A minimal working example would be:
macro eval_line(a, b, x)
isa(a, Real) || (warn("$a is not a real number."); return :(throw(DomainError())))
isa(b, Real) || (warn("$b is not a real number."); return :(throw(DomainError())))
return :($a * $x + $b) # interpolate the variables
end
在这里,@eval_line
宏执行以下操作:
Here, @eval_line
macro does the following:
Main> @macroexpand @eval_line(5, 6, 2)
:(5 * 2 + 6)
如您所见,macro
的参数值在宏内插,并且表达式也相应地提供给用户.当用户没有行为时,
As you can see, the values of macro
's arguments are interpolated inside the macro and the expression is given to the user accordingly. When the user does not behave,
Main> @macroexpand @eval_line([1,2,3], 7, 8)
WARNING: [1, 2, 3] is not a real number.
:((Main.throw)((Main.DomainError)()))
在 parse 时向用户提供用户友好的警告消息,并在运行时抛出DomainError
.
a user-friendly warning message is provided to the user at parse-time, and a DomainError
is thrown at run-time.
当然,您可以在函数中执行这些操作,再次通过对变量进行插值--- 不需要需要使用macro
.但是,最终要实现的是将eval
与返回Expr
的函数的输出结合起来.这就是macro
功能的作用.最后,您只需在macro
名称之前用@
符号调用macro
:
Of course, you can do these things within your functions, again by interpolating the variables --- you do not need to use macro
s. However, what you would like to achieve in the end is to combine eval
with the output of a function that returns Expr
. This is what the macro
functionality is for. Finally, you would simply call your macro
s with an @
sign preceding the macro
name:
Main> @eval_line(5, 6, 2)
16
Main> @eval_line([1,2,3], 7, 8)
WARNING: [1, 2, 3] is not a real number.
ERROR: DomainError:
Stacktrace:
[1] eval(::Module, ::Any) at ./boot.jl:235
编辑1..您可以进一步执行此步骤,并相应地创建函数:
EDIT 1. You can take this one step further, and create functions accordingly:
macro define_lines(linedefs)
for (name, a, b) in eval(linedefs)
ex = quote
function $(Symbol(name))(x) # interpolate name
return $a * x + $b # interpolate a and b here
end
end
eval(ex) # evaluate the function definition expression in the module
end
end
然后,您可以调用此宏以函数形式创建不同的行定义,稍后再调用:
Then, you can call this macro to create different line definitions in the form of functions to be called later on:
@define_lines([
("identity_line", 1, 0);
("null_line", 0, 0);
("unit_shift", 0, 1)
])
identity_line(5) # returns 5
null_line(5) # returns 0
unit_shift(5) # returns 1
编辑2.我猜您可以通过使用类似于以下内容的宏来实现您想要实现的目标:
EDIT 2. You can, I guess, achieve what you would like to achieve by using a macro similar to that below:
macro random_oper(depth, fs, ts)
operations = eval(fs)
oper = operations[rand(1:length(operations))]
terminals = eval(ts)
ts = terminals[rand(1:length(terminals), 2)]
ex = :($oper($ts...))
for d in 2:depth
oper = operations[rand(1:length(operations))]
t = terminals[rand(1:length(terminals))]
ex = :($oper($ex, $t))
end
return ex
end
例如,将给出以下内容:
which will give the following, for instance:
Main> @macroexpand @random_oper(1, [+, -, /], [1,2,3])
:((-)([3, 3]...))
Main> @macroexpand @random_oper(2, [+, -, /], [1,2,3])
:((+)((-)([2, 3]...), 3))
这篇关于使用局部变量评估表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!