使用局部变量评估表达式 [英] Evaluate expression with local variables

查看:56
本文介绍了使用局部变量评估表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个遗传程序,以测试随机生成的表达式的适用性.这里显示的是生成表达式的函数以及主要函数. 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 own eval() 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 with baremodule) has its own 1-argument definition of eval, which evaluates expressions in that module.

我假设您在示例中的Main模块中工作.这就是为什么需要在此处定义全局变量的原因.对于您的问题,可以使用macro s并直接在宏内部插入xy的值.

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 macros 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 macros. 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 macros 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆