你的情况不是普通函数,而是一个代码生成的子领域,叫partial evaluation。
其中这种specify部分参数,得到更优算法的做法,叫staging。
julia有一种方便的,很接近staging的方法, 叫generated function
function goodfunc(x, s = :s1)
gengoodfunc(x, Val(s))
end
@generated function gengoodfunc(x, ::Val{S}) where S
Dict(
:s1 => :(y -> y + x),
:s2 => :(y -> y * x)
)[S]
end
generated形式上并不处理任意staging,只针对类型的staging(但可以处理不可变值的staging, 见后)
更general的staging可以通过eval来做,比如下列做法:
function goodfunc(x, s = :s1)
gengoodfunc(x, s)
end
function gengoodfunc(x, s)
Dict(
:s1 => () -> :(y -> y + $x),
:s2 => () -> :(y -> y * $x)
)[s]() |> @__MODULE__.eval
end
值得注意的是,generated function比起general purpose的staging有一个好处,那就是不需要人工手工生成staged的函数。
例如上面两段代码,使用generated func时,无数次调用goodfunc
只生成一次代码,而使用后者的general staging时,每次调用goodfunc
均生成一次代码,这也意味着真正使用general staging函数时,需要先手动生成staged函数,然后多次调用staged结果。
而为什么generared func有这个好处,是因为它可以通过multiple dispatch对staging结果进行cache( 同时由于是multi dispatch, 还可以尽可能的静态编译 )。general staging不保证能cache,因为参数类型不一定hashable。
multiple dispatch支持分派不可变值(在trait角度讲,immutable <: hashable),所以generated func的表达力上界是staging时要specify的参数是immutable的任何情况。
This is the whole story.
最后。
动态修改作用域的语言确实存在,例如python的locals(),你可以按名(一个运行时字符串)访问变量,但不能添加新的变量符号,且开销巨大。
julia中如果你想这么做也是有办法的,不要eval(s), 类似py, 使用 (@locals)[s],需要julia1.1+。