Julia 宏保存函数的公开形式并定义它

Julia Macro to Save the Overt form of a Function, and Define it

我正在编写的模拟的一些参数是函数。当生成输出时,我想将这些功能参数的定义放在输出中。我想到了一个宏,它以某种方式将定义保存为字符串,然后定义它。例如,这是我现在所做的:

borda_score_fn(p) = exp(1/p)                                                                                                                 
global g_borda_score_fn_string = "exp(1/p)"   

然后我将 g_borda_score_fn_string 写入我的输出。但这真的很丑!

我想做的是这样的:

@paramfn borda_score_fn(p) = exp(1/p)

并且稍后能够同时调用 borda_score_fn(p),并使表单(即“exp(1/p)”)可用于写入我的输出日志。 (字符串形式可能会隐藏在全局字典中,实际上,它们都可以。)

我已经尝试了很多版本,但无法获得正确的解析和调用集来使其正常工作。任何帮助将不胜感激。

这可能与您的想法有点不同,但一种可能是“Julian”的方法可能是通过多重分派让函数本身 return 表单字符串,而不是定义一个全新的全局变量就是为了这个。例如,假设我们有一个类型

struct Form end

我们可以用来调度,然后我们可以写

borda_score_fn(p) = exp(1/p)
borda_score_fn(::Form) = "exp(1/p)"

然后可以通过使用我们的类型调用函数来检索它

julia> borda_score_fn(2)
1.6487212707001282

julia> borda_score_fn(Form())
"exp(1/p)"

这本身可能并不坏。但是,如果您希望宏同时执行这两个部分,那么可以使用

macro paramfn(e)
    name = esc(e.args[1].args[1])
    str = string(e.args[2].args[2])
    f = esc(e)
    quote
        $name(::Form) = $str
        $f
    end
end

会让你写

julia> @paramfn borda_score_fn(p) = exp(1/p)
borda_score_fn (generic function with 2 methods)

julia> borda_score_fn(1)
2.718281828459045

julia> borda_score_fn(Form())
"exp(1 / p)"

为了完整起见,您可以通过以下方式以更类似于您的原始方法但比使用全局变量更惯用的方式来完成此操作:

julia> module FormOf
           export formof, @paramfn
           
           function formof end
           macro paramfn(expr)
               name = esc(expr.args[1].args[1])
               form_str = string(expr.args[2].args[2])
               quote
                   $(esc(expr))
                   $FormOf.formof(::typeof($name)) = $form_str
                   $name
               end
           end
       end
Main.FormOf

julia> FormOf.@paramfn borda_score_fn(p) = exp(1/p)
borda_score_fn (generic function with 1 method)

julia> FormOf.formof(borda_score_fn)
"exp(1 / p)"

但是,由于它定义了FormOf.formof的新方法,所以这只适用于全局范围:

julia> function bla()
           FormOf.@paramfn fn(p) = exp(1/p)
           fn(10) + 1
       end

ERROR: syntax: Global method definition around REPL[45]:10 needs to be placed at the top level, or use "eval".
Stacktrace:
 [1] top-level scope
   @ REPL[50]:1

@cbk的方案没有这个限制