我认为(评论区字数不够,所以我把它作为答案)在这种情况下,可能最好是类型不稳定的。请注意,这正是Julia本身所做的:
julia> x = :(1+2*(3+4))
:(1 + 2 * (3 + 4))
julia> dump(x)
Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol +
2: Int64 1
3: Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol *
2: Int64 2
3: Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol +
2: Int64 3
3: Int64 4
当然,Julia有着更加丰富的语法,但即使在你的简单情况下也要考虑以下内容。如果您编译代码的某个部分一次,然后以这种或其他形式运行它多次,您将获得类型稳定性的好处。
现在我假设您所写的内容实际上大多只会被评估一次。如果您使表达式完全类型稳定,每次都必须付出代价(假设表达式发生变化):
1. 编译它的成本(昂贵)。
2. 运行它的成本(相对便宜)。
如果您的代码是类型不稳定的,您只需要支付一次编译成本。的确,运行速度会稍慢,但总体来说,这种方式可能更好。
另一方面 - 如果您希望只定义一次表达式,然后多次运行它,那么可能更好的方法是使用元编程:
1. 仅处理您的表达式
一次并生成将评估您的表达式的Julia代码。
2. 然后Julia将编译生成的代码一次。
3. 在完成步骤1和2之后执行它可以获得最大的执行性能。
对于你的问题,一种半成品解决方案是使用以下数据结构:
struct Binary{T <: BinaryKind, S} <: Operation
xs::Vector{S}
end
这样,如果
S
是一个具体类型或者是由少数几个具体类型组成的小型联合类型,你的代码将会是类型稳定的;否则就是类型不稳定的(我预计此时你可以尝试让其余代码以一种方式生成
xs
,使得它的
eltype
是具体类型或者是由少数几个具体类型组成的小型联合类型)。如有更多问题,请在评论区留言,我可以详细解答。
D
。除非限制有特定目的,否则您可以使用struct Binary{T <: BinaryKind, D} <: Operation
。 - DNF