在Julia中生成函数

3

我有两个函数

"This is my docstring for `add_1(x)`"
add_1(x) = x + 1

"This is my docstring for `add_2(x)`"
add_2(x) = x + 2

这两个函数的代码非常相似,在Julia中一定有一种聪明的方式可以自动创建它们。

附属问题:如果这些函数是通过程序生成的,那么错误会如何处理?通常堆栈跟踪会显示来自原始文件的行号,但是在这里,几个函数都是从同一行生成的。是否总是显示相同的行号呢?

2个回答

2

一种解决方案是这样的

["""
"This is my docstring for \`add_$i(x)\`"
add_$i(x) = x + $i
""" for i ∈ 1:3] .|> Meta.parse .|> eval

关于行号,我卡住了。这是故意引发错误后得到的结果:

julia> add_3("arstoen")
ERROR: MethodError: no method matching +(::String, ::Int64)
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:560
  +(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16,         UInt32, UInt64, UInt8} at int.jl:87
  +(::LinearAlgebra.UniformScaling, ::Number) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/uniformscaling.jl:145
  ...
Stacktrace:
 [1] add_3(x::String)
   @ Main ./none:2
 [2] top-level scope
   @ REPL[8]:1

还有其他人知道如何使堆栈跟踪更加合理吗?


我建议将此作为您问题的一部分移动,因为您实际上是在询问如何将行号信息注入生成的代码中。 - Przemyslaw Szufel
常规的做法是 for i in 1:3; fn = Symbol(:add_, i); @eval $fn(x) = x + $i; end, 这应该可以得到行号。 - mcabbott

1

您需要手动构建代码的抽象语法树(AST),并注入适当的 LineNumberNode

让我们从一些AST开始。通常最容易让Julia在开始时生成初始AST,然后进行变异。

code = quote
  add_1(x) = x+1
end

尝试运行dump(code)以查看AST(我在此省略输出,因为输出很长)。

现在我们可以改变它来生成add_2。您可以将下面的代码放入函数中,并生成您想要的许多变体add_n,但为了可读性,我只关注add_2

code.args[1] = LineNumberNode(2, Symbol("My line of add_2"))
code.args[2].args[1] = :(add_2(x))
code.args[2].args[2].args[1] =  LineNumberNode(2, Symbol("My function body of add two"))
code.args[2].args[2].args[2].args[3]=2

那就太好了!您已经拥有了自定义行号的自定义函数。我们来测试一下吧!
julia> eval(code)
add_2 (generic function with 1 method)

julia> add_2(4)
6

julia> add_2("will errror")
ERROR: MethodError: no method matching +(::String, ::Int64)
  [...]
Stacktrace:
 [1] add_2(x::String)
   @ Main .\My function body of add two:2
 [2] top-level scope
   @ REPL[22]:1

你可以看到,你可以随意注入任何位置信息到生成代码中。
更多阅读请查看:https://docs.julialang.org/en/v1/devdocs/ast/

具体而言,您可以基于 @__LINE__@__FILE__ 注入信息。 - phipsgabler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接