eval in function scope (accessing function args)

2019-03-03 18:33发布

Given:

abstract ABSGene
type NuGene <: Genetic.ABSGene
     fqnn::ANN
     dcqnn::ANN
     score::Float32
 end

 function mutate_copy{T<:ABSGene}(gene::T)
     all_fields_except_score = filter(x->x != :score, names(T))
     all_fields_except_score =  map(x->("mutate_copy(gene.$x)"),all_fields_except_score)
     eval(parse("$(T)("*join(all_fields_except_score,",")*")"))
 end

 ng = NuGene()

 mutated_ng = mutate_copy(ng)

results in:

ERROR: gene not defined
in mutate_copy at none:4

If I just look at it as a string (prior to running parse and eval) it looks fine:

"NuGene(mutate_copy(gene.fqnn),mutate_copy(gene.dcqnn))"

However, eval doesn't seem to know about gene that has been passed into the mutate_copy function.

How do I access the gene argument that's been passed into the mutate copy?

I tried this:

function mutate_copy{T<:ABSGene}(gene::T)
  all_fields_except_score = filter(x->x != :score, names(T))
  all_fields_except_score =  map(x->   ("mutate_copy($gene.$x)"),all_fields_except_score)
  eval(parse("$(T)("*join(all_fields_except_score,",")*")"))

end

But that expands the gene in the string which is not what I want.

标签: eval julia
1条回答
爷、活的狠高调
2楼-- · 2019-03-03 18:40

Don't use eval! In almost all cases, unless you really know what you're doing, you shouldn't be using eval. And in this case, eval simply won't work because it operates in the global (or module) scope and doesn't have access to the variables local to the function (like the argument gene).

While the code you posted isn't quite enough for a minimal working example, I can take a few guesses as to what you want to do here.

Instead of map(x->("mutate_copy(gene.$x)"),all_fields_except_score), you can dynamically look up the field name:

map(x->mutate_copy(gene.(x)), all_fields_except_score)

This is a special syntax that may eventually be replaced by getfield(gene, x). Either one will work right now, though.

And then instead of eval(parse("$(T)("*join(all_fields_except_score,",")*")")), call T directly and "splat" the field values:

T(all_fields_except_score...)

I think the field order should be stable through all those transforms, but it looks a pretty fragile (you're depending on the score being the last field, and all constructors to have their arguments in the same order as their fields). It looks like you're trying to perform a deepcopy sort of operation, but leaving the score field uninitialized. You could alternatively use Base's deepcopy and then recursively set the scores to zero.

查看更多
登录 后发表回答