编写 Julia 宏 returns 一个函数
Write Julia macro that returns a function
先post到这里,感谢阅读!
问题:我有一个 Vector{String}
- 称之为 A
- 其中每个元素都是等式的一部分,例如A
的第一个元素是 "x[1] - (0.8*x[1])"
。我想写一个宏作为参数 i) a String
- 调用它 fn_name
- 用一个函数的名字,ii) 向量 A
,和 returns 一个名为 fn_name
的函数看起来像
function fn_name(f, x)
f[1] = x[1] - (0.8*x[1])
f[2] = (exp(x[4]) - 0.8*exp(x[3]))^(-1.1) - (0.99*(exp(x[4]) - 0.8*exp(x[4]))^(-1.1)*(1.0 - 0.025 + 0.30*exp(x[1])*exp(x[2])^(0.30 - 1.0)))
f[3] = exp(x[2]) - ((1.0 - 0.025)*exp(x[2]) + exp(x[1])*exp(x[2])^0.30 - exp(x[4]))
f[4] = x[3] - (x[4])
end
其中每个 rhs 是
的一个元素
A = ["x[1] - (0.8*x[1])", "(exp(x[4]) - 0.8*exp(x[3]))^(-1.1) - (0.99*(exp(x[4]) - 0.8*exp(x[4]))^(-1.1)*(1.0 - 0.025 + 0.30*exp(x[1])*exp(x[2])^(0.30 - 1.0)))", "exp(x[2]) - ((1.0 - 0.025)*exp(x[2]) + exp(x[1])*exp(x[2])^0.30 - exp(x[4]))", "x[3] - (x[4])"]
我的尝试:解决问题的最佳尝试如下
macro make_fn(fn_name, A)
esc(quote
function $(Symbol(fn_name))(f, x)
for i = 1:length($(A))
f[$i] = Meta.parse($(A)[$i])
end
end
end)
end
然而这不起作用:当我 运行 @make_fn("my_name", A)
我得到错误 LoadError: UndefVarError: i not defined
.
我发现很难全神贯注于 Julia 元编程,虽然我很乐意避免使用它,但我认为对于这个问题它是不可避免的。
你能帮我理解我的错误在哪里吗?
谢谢
这种情况下的宏不仅是可以避免的,甚至是不适用的,除非 A
在编译时是已知的。
我可以使用 eval
和一些闭包提供解决方案:
julia> function make_fn2(A)
Af = [@eval(x -> $(Meta.parse(expr))) for expr in A]
function (f, x)
for i in eachindex(A, f)
f[i] = Af[i](x)
end
return f
end
end
make_fn2 (generic function with 1 method)
julia> fn_name = make_fn2(A)
#46 (generic function with 1 method)
julia> fn_name(zeros(4), [1,2,3,4])
4-element Array{Float64,1}:
0.19999999999999996
-0.06594092302655707
49.82984401122239
-1.0
有
的限制
eval
将在定义 this 的模块的全局范围内评估表达式(因此它可能与调用函数的范围不同),并且
- 只有当您首先 return 到全局范围时,新创建的函数才会起作用(即,如果您尝试 运行 在您创建它的函数中它不会起作用)。
但我真的建议考虑一种比字符串更好的输入格式。
先post到这里,感谢阅读!
问题:我有一个 Vector{String}
- 称之为 A
- 其中每个元素都是等式的一部分,例如A
的第一个元素是 "x[1] - (0.8*x[1])"
。我想写一个宏作为参数 i) a String
- 调用它 fn_name
- 用一个函数的名字,ii) 向量 A
,和 returns 一个名为 fn_name
的函数看起来像
function fn_name(f, x)
f[1] = x[1] - (0.8*x[1])
f[2] = (exp(x[4]) - 0.8*exp(x[3]))^(-1.1) - (0.99*(exp(x[4]) - 0.8*exp(x[4]))^(-1.1)*(1.0 - 0.025 + 0.30*exp(x[1])*exp(x[2])^(0.30 - 1.0)))
f[3] = exp(x[2]) - ((1.0 - 0.025)*exp(x[2]) + exp(x[1])*exp(x[2])^0.30 - exp(x[4]))
f[4] = x[3] - (x[4])
end
其中每个 rhs 是
的一个元素A = ["x[1] - (0.8*x[1])", "(exp(x[4]) - 0.8*exp(x[3]))^(-1.1) - (0.99*(exp(x[4]) - 0.8*exp(x[4]))^(-1.1)*(1.0 - 0.025 + 0.30*exp(x[1])*exp(x[2])^(0.30 - 1.0)))", "exp(x[2]) - ((1.0 - 0.025)*exp(x[2]) + exp(x[1])*exp(x[2])^0.30 - exp(x[4]))", "x[3] - (x[4])"]
我的尝试:解决问题的最佳尝试如下
macro make_fn(fn_name, A)
esc(quote
function $(Symbol(fn_name))(f, x)
for i = 1:length($(A))
f[$i] = Meta.parse($(A)[$i])
end
end
end)
end
然而这不起作用:当我 运行 @make_fn("my_name", A)
我得到错误 LoadError: UndefVarError: i not defined
.
我发现很难全神贯注于 Julia 元编程,虽然我很乐意避免使用它,但我认为对于这个问题它是不可避免的。
你能帮我理解我的错误在哪里吗?
谢谢
这种情况下的宏不仅是可以避免的,甚至是不适用的,除非 A
在编译时是已知的。
我可以使用 eval
和一些闭包提供解决方案:
julia> function make_fn2(A)
Af = [@eval(x -> $(Meta.parse(expr))) for expr in A]
function (f, x)
for i in eachindex(A, f)
f[i] = Af[i](x)
end
return f
end
end
make_fn2 (generic function with 1 method)
julia> fn_name = make_fn2(A)
#46 (generic function with 1 method)
julia> fn_name(zeros(4), [1,2,3,4])
4-element Array{Float64,1}:
0.19999999999999996
-0.06594092302655707
49.82984401122239
-1.0
有
的限制eval
将在定义 this 的模块的全局范围内评估表达式(因此它可能与调用函数的范围不同),并且- 只有当您首先 return 到全局范围时,新创建的函数才会起作用(即,如果您尝试 运行 在您创建它的函数中它不会起作用)。
但我真的建议考虑一种比字符串更好的输入格式。