我正在尝试构建一个函数,该函数将输出要分配给新内存函数的表达式。我可能误解了元编程的能力,但是,我正在尝试构建一个函数来生成数学系列并将其分配给一个函数,例如:
主文件
function series(iter)
S = ""
for i in 1:iter
a = "x^$i + "
S = S*a
end
return chop(S, tail=3)
end
Run Code Online (Sandbox Code Playgroud)
所以,这将构建模式,我暂时在 repl 中使用它:
julia> a = Meta.parse(series(4))
:(x ^ 1 + x ^ 2 + x ^ 3 + x ^ 4)
julia> f =eval(Meta.parse(series(4)))
120
julia> f(x) =eval(Meta.parse(series(4)))
ERROR: cannot define function f; it already has a value
Run Code Online (Sandbox Code Playgroud)
显然 eval 在这种情况下不是我要找的,但是,我可以使用另一个函数吗?或者,这不是在 Julia 中完成任务的可行方法吗?
你得到的实际错误与元编程无关,但事实上你正在重新分配f
,它之前被分配了一个值:
julia> f = 10
10
julia> f(x) = x + 1
ERROR: cannot define function f; it already has a value
Stacktrace:
[1] top-level scope at none:0
[2] top-level scope at REPL[2]:1
Run Code Online (Sandbox Code Playgroud)
它只是不喜欢那样。以不同方式调用这些变量中的任何一个。
现在是概念问题。首先,你在这里做的不是 Julia 中的“正确”元编程:为什么要处理字符串和解析?您可以直接处理表达式:
julia> function series(N)
S = Expr(:call, :+)
for i in 1:N
push!(S.args, :(x ^ $i))
end
return S
end
series (generic function with 1 method)
julia> series(3)
:(x ^ 1 + x ^ 2 + x ^ 3)
Run Code Online (Sandbox Code Playgroud)
这利用了+
属于在重复应用程序中自动收集的表达式类的事实。
其次,你没有eval
在适当的地方打电话。我假设你的意思是“给我 的功能x
,身体是series(4)
返回的东西”。现在,虽然以下工作:
julia> f3(x) = eval(series(4))
f3 (generic function with 1 method)
julia> f3(2)
30
Run Code Online (Sandbox Code Playgroud)
这并不理想,因为每次调用函数时都会重新编译主体。如果你做类似的事情,最好在函数定义时将代码扩展到主体中:
julia> @eval f2(x) = $(series(4))
f2 (generic function with 1 method)
julia> f2(2)
30
Run Code Online (Sandbox Code Playgroud)
你只需要在这里注意卫生。一切都取决于这样一个事实,即您知道生成的主体是根据 制定的x
,并且函数参数与之匹配。在我看来,实现你的想法最朱利安的方式是通过一个宏:
julia> macro series(N::Int, x)
S = Expr(:call, :+)
for i in 1:N
push!(S.args, :($x ^ $i))
end
return S
end
@series (macro with 1 method)
julia> @macroexpand @series(4, 2)
:(2 ^ 1 + 2 ^ 2 + 2 ^ 3 + 2 ^ 4)
julia> @series(4, 2)
30
Run Code Online (Sandbox Code Playgroud)
输出中没有剩余的自由变量。
最后,正如评论中所指出的,evalpoly
Base 中有一个函数(和相应的宏)可以概括您的用例。请注意,此功能对不使用代码生成-它采用了精心设计的生成的函数,其与在代码是优化结果组合通常等于宏生成的代码。
归档时间: |
|
查看次数: |
118 次 |
最近记录: |