【发布时间】:2016-06-08 18:07:53
【问题描述】:
这是为了简化我向here提出的问题的一部分:
我想编写一些代码,保证在满足特定条件的类型上工作。假设今天我写了一些代码:
immutable Example
whatever::ASCIIString
end
function step_one(x::Example)
length(x.whatever)
end
function step_two(x::Int64)
(x * 2.5)::Float64
end
function combine_two_steps{X}(x::X)
middle = step_one(x)
result = step_two(middle)
result
end
x = Example("Hi!")
combine_two_steps(x)
运行这个工程:
julia> x = Example("Hi!")
Example("Hi!")
julia> combine_two_steps(x)
7.5
然后改天我又写了一些代码:
immutable TotallyDifferentExample
whatever::Bool
end
function step_one(x::TotallyDifferentExample)
if x.whatever
"Hurray"
else
"Boo"
end
end
function step_two(x::ASCIIString)
(Int64(Char(x[end])) * 1.5)::Float64
end
你知道吗,我的通用合并函数仍然有效!
julia> y = TotallyDifferentExample(false)
TotallyDifferentExample(false)
julia> combine_two_steps(y)
166.5
万岁!但是,假设现在是深夜,我正试图在第三个示例中再次执行此操作。我记得实现step_one,但是我忘记实现step_two!
immutable ForgetfulExample
whatever::Float64
end
function step_one(x::ForgetfulExample)
x.whatever+1.0
end
现在当我运行它时,我会得到一个运行时错误!
julia> z = ForgetfulExample(1.0)
ForgetfulExample(1.0)
julia> combine_two_steps(z)
ERROR: MethodError: `step_two` has no method matching step_two(::Float64)
现在,我为一位经理工作,如果我遇到运行时错误,他会杀了我。所以为了挽救我的生命,我需要做的是编写一个 Trait,它基本上说“如果类型实现了这个 trait,那么调用 combine_two_steps 是安全的。”
我想写一些类似的东西
using Traits
@traitdef ImplementsBothSteps{X} begin
step_one(X) -> Y
step_two(Y) -> Float64
end
function combine_two_steps{X;ImplementsBothSteps{X}}(x::X)
middle = step_one(x)
result = step_two(middle)
result
end
b/c 然后我知道 如果 combine_two_steps 曾经调度,那么它将 运行而不会引发错误这些方法不存在。
等效地,istrait(ImplementsBothSteps{X})(为真)等效于 combine_two_steps 将运行而不会出现所需方法不存在错误。
但是,众所周知,我不能使用该特征定义,因为Y 没有任何意义。 (事实上,奇怪的是代码编译没有错误,
julia> @traitdef ImplementsBothSteps{X} begin
step_one(X) -> Y
step_two(Y) -> Float64
end
julia> immutable Example
whatever::ASCIIString
end
julia> function step_one(x::Example)
length(x.whatever)::Int64
end
step_one (generic function with 1 method)
julia> function step_two(x::Int64)
(x * 2.5)::Float64
end
step_two (generic function with 1 method)
julia> istrait(ImplementsBothSteps{Example})
false
但类型不满足特征,即使某些 Y 存在方法。)我的第一个想法是我可以将 Y 更改为 Any 之类的东西
using Traits
@traitdef ImplementsBothSteps{X} begin
step_one(X) -> Any
step_two(Any) -> Float64
end
但这也失败了 b/c Any 真的应该是类似于 Some 的东西,而不是字面上的 Any 类型(因为我从未实现过可以将任何类型作为输入的方法 step_two) ,但某些特定类型在两行之间共享!
所以,问题是:在这种情况下你会怎么做?您想传递一个“规范”(此处以 Trait 表示的合同的形式),以保证任何符合规范的程序员都能够使用您的函数combine_two_steps,但规范本质上具有存在量词的定义。
有解决方法吗?编写“规范”的更好方法(例如“不要使用 Traits,使用其他东西”?)等等。
顺便说一句,这听起来可能有点做作,但上述链接的问题和这个问题在我正在进行的项目中经常出现。我基本上陷入了由这个问题引起的障碍,并且有一些丑陋的变通办法可以根据具体情况进行处理,但没有针对一般情况的方法。
【问题讨论】:
标签: generics julia abstraction traits