如何在不使用 eval 的情况下从符号中获取函数?
How to get a function from a symbol without using eval?
我有一个符号代表要调用的函数的名称:
julia> func_sym = :tanh
我可以使用该符号获取 tanh 函数并使用以下方式调用它:
julia> eval(func_sym)(2)
0.9640275800758169
但我宁愿避免使用 'eval',因为它会被调用很多次而且很昂贵(并且 func_sym 可以根据上下文有几个不同的值)。
IIRC 在 Ruby 你可以这样说:
obj.send(func_sym, args)
Julia 中有类似的东西吗?
编辑:关于为什么我有用符号表示的函数的更多细节:
我有一个包含激活函数的类型(来自神经网络),最初我将其作为函数包含在内:
type NeuralLayer
weights::Matrix{Float32}
biases::Vector{Float32}
a_func::Function
end
然而,我需要使用 JLD 将这些东西序列化到文件中,但是序列化函数是不可能的,所以我使用了一个符号:
type NeuralLayer
weights::Matrix{Float32}
biases::Vector{Float32}
a_func::Symbol
end
目前我使用上面的 eval 方法调用激活函数。有 NeuralLayers 的集合,每个都可以有自己的激活函数。
But I'd rather avoid the 'eval' there as it will be called many times and it's expensive (and func_sym can have several different values depending on context).
这种动态调度在 Julia 中是可行的,但不推荐。根据上下文更改 'func_sym' 的值会破坏类型推断以及方法特化和内联。相反,推荐的方法是使用手册的 multiple dispatch, as detailed in the Methods 部分。
@Isaiah 的回答很到位;在对原始问题进行编辑之后可能更是如此。为了详细说明并使它更适合您的情况:我会将您的 NeuralLayer
类型更改为参数类型:
type NeuralLayer{func_type}
weights::Matrix{Float32}
biases::Vector{Float32}
end
由于func_type
没有出现在字段的类型中,构造函数将要求您显式指定它:layer = NeuralLayer{:excitatory}(w, b)
。这里的一个限制是您不能修改类型参数。
现在,func_type
可以是一个符号(就像您现在所做的那样),也可以是一个功能更相关的参数(或多个参数),用于调整您的激活函数。然后你像这样定义你的激活函数:
# If you define your NeuralLayer with just one parameter:
activation(layer::NeuralLayer{:inhibitory}) = …
activation(layer::NeuralLayer{:excitatory}) = …
# Or if you want to use several physiological parameters instead:
activation{g_K,g_Na,g_l}(layer::NeuralLayer{g_K,g_Na,g_l} = f(g_K, g_Na, g_l)
关键是函数和行为对于数据来说是外部的。使用类型定义和抽象类型层次结构来定义行为,就像在外部函数中编码的那样……但只将数据本身存储在类型中。这与 Python 或其他强烈面向对象的范例截然不同,需要一些时间来适应。
我有一个符号代表要调用的函数的名称:
julia> func_sym = :tanh
我可以使用该符号获取 tanh 函数并使用以下方式调用它:
julia> eval(func_sym)(2)
0.9640275800758169
但我宁愿避免使用 'eval',因为它会被调用很多次而且很昂贵(并且 func_sym 可以根据上下文有几个不同的值)。
IIRC 在 Ruby 你可以这样说:
obj.send(func_sym, args)
Julia 中有类似的东西吗?
编辑:关于为什么我有用符号表示的函数的更多细节:
我有一个包含激活函数的类型(来自神经网络),最初我将其作为函数包含在内:
type NeuralLayer
weights::Matrix{Float32}
biases::Vector{Float32}
a_func::Function
end
然而,我需要使用 JLD 将这些东西序列化到文件中,但是序列化函数是不可能的,所以我使用了一个符号:
type NeuralLayer
weights::Matrix{Float32}
biases::Vector{Float32}
a_func::Symbol
end
目前我使用上面的 eval 方法调用激活函数。有 NeuralLayers 的集合,每个都可以有自己的激活函数。
But I'd rather avoid the 'eval' there as it will be called many times and it's expensive (and func_sym can have several different values depending on context).
这种动态调度在 Julia 中是可行的,但不推荐。根据上下文更改 'func_sym' 的值会破坏类型推断以及方法特化和内联。相反,推荐的方法是使用手册的 multiple dispatch, as detailed in the Methods 部分。
@Isaiah 的回答很到位;在对原始问题进行编辑之后可能更是如此。为了详细说明并使它更适合您的情况:我会将您的 NeuralLayer
类型更改为参数类型:
type NeuralLayer{func_type}
weights::Matrix{Float32}
biases::Vector{Float32}
end
由于func_type
没有出现在字段的类型中,构造函数将要求您显式指定它:layer = NeuralLayer{:excitatory}(w, b)
。这里的一个限制是您不能修改类型参数。
现在,func_type
可以是一个符号(就像您现在所做的那样),也可以是一个功能更相关的参数(或多个参数),用于调整您的激活函数。然后你像这样定义你的激活函数:
# If you define your NeuralLayer with just one parameter:
activation(layer::NeuralLayer{:inhibitory}) = …
activation(layer::NeuralLayer{:excitatory}) = …
# Or if you want to use several physiological parameters instead:
activation{g_K,g_Na,g_l}(layer::NeuralLayer{g_K,g_Na,g_l} = f(g_K, g_Na, g_l)
关键是函数和行为对于数据来说是外部的。使用类型定义和抽象类型层次结构来定义行为,就像在外部函数中编码的那样……但只将数据本身存储在类型中。这与 Python 或其他强烈面向对象的范例截然不同,需要一些时间来适应。