如何使用函数参数进行元编程?
How to use metaprogramming with function args?
这是我学习和体验 Julia 的第二天。尽管我仔细阅读了有关元编程的文档(但可能不够仔细)和几个类似的线程。我仍然不知道如何在函数中使用它。
我试图使以下功能更灵活地模拟一些数据:
using Distributions
function gendata(N,NLATENT,NITEMS)
latent = repeat(rand(Normal(6,2),N,NLATENT), inner=(1,NITEMS))
errors = rand(Normal(0,1),N,NLATENT*NITEMS)
x = latent+errors
end
通过这样做:
using Distributions
function gendata(N,NLATENT,NITEMS,LATENT_DIST="Normal(0,1)",ERRORS_DIST="Normal(0,1)")
to_eval_latent = parse("latent = repeat(rand($LATENT_DIST,N,NLATENT), inner=(1,NITEMS))")
eval(to_eval_latent)
to_eval_errors = parse("error = rand($ERRORS_DIST,N,NLATENT*NITEMS)")
eval(to_eval_errors)
x = latent+errors
end
但是由于 eval 不适用于本地范围,因此它不起作用。我该怎么做才能解决这个问题?
还有原来的功能,好像没有那么快,我是不是在性能上有什么大的失误?
非常感谢任何推荐。
提前致谢。
那里不需要使用 eval,您可以通过将分布类型作为关键字参数(或具有默认值的命名参数)传递来保持相同的灵活性。解析和评估 "stringly-typed" 参数通常会破坏优化,应该避免。
function gendata(N,NLATENT,NITEMS; LATENT_DIST=Normal(0,1),ERRORS_DIST=Normal(0,1))
latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS))
errors = rand(ERRORS_DIST,N,NLATENT*NITEMS)
x = latent+errors
end
julia> gendata(10,2,3, LATENT_DIST=Pareto(.3))
...
julia> gendata(10,2,3, ERRORS_DIST=Gamma(.6))
...
等等
你真的不应该在这里使用 eval
(速度较慢,不会产生类型信息,会干扰编译等)但如果你想了解哪里出了问题,这里是你会怎么做:
要么将其与其余代码分开:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
# Eval your expressions separately
LATENT_DIST = eval(parse(LDIST_EX))
ERRORS_DIST = eval(parse(EDIST_EX))
# Do your thing
latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS))
errors = rand(ERROR_DIST,N,NLATENT*NITEMS)
x = latent+errors
end
或使用带引号的表达式进行插值:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
# Obtain expression objects
LATENT_DIST = parse(LDIST_EX)
ERRORS_DIST = parse(EDIST_EX)
# Eval but interpolate in everything that's local to the function
# And you can't introduce local variables with eval so keep them
# out of it.
latent = eval( :(repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS))) )
errors = eval( :(rand($ERRORS_DIST, $N, $NLATENT*$NITEMS)) )
x = latent+errors
end
您还可以使用带有 let 块的单个 eval 来引入自包含范围:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
LATENT_DIST = parse(LDIST_EX)
ERRORS_DIST = parse(EDIST_EX)
x =
@eval let
latent = repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS))
errors = (rand($ERRORS_DIST, $N, $NLATENT*$NITEMS))
latent+errors
end
end
((@eval x) == eval(:(x)))
好吧,希望你能更好地理解 eval
这件事。第二天,我的意思是,你应该尝试一下 ;)
这是我学习和体验 Julia 的第二天。尽管我仔细阅读了有关元编程的文档(但可能不够仔细)和几个类似的线程。我仍然不知道如何在函数中使用它。 我试图使以下功能更灵活地模拟一些数据:
using Distributions
function gendata(N,NLATENT,NITEMS)
latent = repeat(rand(Normal(6,2),N,NLATENT), inner=(1,NITEMS))
errors = rand(Normal(0,1),N,NLATENT*NITEMS)
x = latent+errors
end
通过这样做:
using Distributions
function gendata(N,NLATENT,NITEMS,LATENT_DIST="Normal(0,1)",ERRORS_DIST="Normal(0,1)")
to_eval_latent = parse("latent = repeat(rand($LATENT_DIST,N,NLATENT), inner=(1,NITEMS))")
eval(to_eval_latent)
to_eval_errors = parse("error = rand($ERRORS_DIST,N,NLATENT*NITEMS)")
eval(to_eval_errors)
x = latent+errors
end
但是由于 eval 不适用于本地范围,因此它不起作用。我该怎么做才能解决这个问题?
还有原来的功能,好像没有那么快,我是不是在性能上有什么大的失误?
非常感谢任何推荐。 提前致谢。
那里不需要使用 eval,您可以通过将分布类型作为关键字参数(或具有默认值的命名参数)传递来保持相同的灵活性。解析和评估 "stringly-typed" 参数通常会破坏优化,应该避免。
function gendata(N,NLATENT,NITEMS; LATENT_DIST=Normal(0,1),ERRORS_DIST=Normal(0,1))
latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS))
errors = rand(ERRORS_DIST,N,NLATENT*NITEMS)
x = latent+errors
end
julia> gendata(10,2,3, LATENT_DIST=Pareto(.3))
...
julia> gendata(10,2,3, ERRORS_DIST=Gamma(.6))
...
等等
你真的不应该在这里使用 eval
(速度较慢,不会产生类型信息,会干扰编译等)但如果你想了解哪里出了问题,这里是你会怎么做:
要么将其与其余代码分开:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
# Eval your expressions separately
LATENT_DIST = eval(parse(LDIST_EX))
ERRORS_DIST = eval(parse(EDIST_EX))
# Do your thing
latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS))
errors = rand(ERROR_DIST,N,NLATENT*NITEMS)
x = latent+errors
end
或使用带引号的表达式进行插值:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
# Obtain expression objects
LATENT_DIST = parse(LDIST_EX)
ERRORS_DIST = parse(EDIST_EX)
# Eval but interpolate in everything that's local to the function
# And you can't introduce local variables with eval so keep them
# out of it.
latent = eval( :(repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS))) )
errors = eval( :(rand($ERRORS_DIST, $N, $NLATENT*$NITEMS)) )
x = latent+errors
end
您还可以使用带有 let 块的单个 eval 来引入自包含范围:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
LATENT_DIST = parse(LDIST_EX)
ERRORS_DIST = parse(EDIST_EX)
x =
@eval let
latent = repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS))
errors = (rand($ERRORS_DIST, $N, $NLATENT*$NITEMS))
latent+errors
end
end
((@eval x) == eval(:(x)))
好吧,希望你能更好地理解 eval
这件事。第二天,我的意思是,你应该尝试一下 ;)