说我有一个朱莉娅性状,其涉及两种类型:一种类型是一种"基地"类型的可满足一种局部性状,另一种是一个相关联的是唯一地由基类型确定类型.(也就是说,BaseType - > AssociatedType的关系是一个函数.)这些类型一起满足了我感兴趣的复合特征.
例如:
using Traits
@traitdef IsProduct{X} begin
isnew(X) -> Bool
coolness(X) -> Float64
end
@traitdef IsProductWithMeasurement{X,M} begin
@constraints begin
istrait(IsProduct{X})
end
measurements(X) -> M
#Maybe some other stuff that dispatches on (X,M), e.g.
#fits_in(X,M) -> Bool
#how_many_fit_in(X,M) -> Int64
#But I don't want to implement these now
end
Run Code Online (Sandbox Code Playgroud)
现在这里有几个示例类型.请忽略示例的细节; 它们仅仅意味着MWE,细节上没有任何相关内容:
type Rope
color::ASCIIString
age_in_years::Float64
strength::Float64
length::Float64
end
type Paper
color::ASCIIString
age_in_years::Int64
content::ASCIIString
width::Float64
height::Float64
end
function isnew(x::Rope)
(x.age_in_years < 10.0)::Bool
end
function coolness(x::Rope)
if x.color=="Orange"
return 2.0::Float64
elseif x.color!="Taupe"
return 1.0::Float64
else
return 0.0::Float64
end
end
function isnew(x::Paper)
(x.age_in_years < 1.0)::Bool
end
function coolness(x::Paper)
(x.content=="StackOverflow Answers" ? 1000.0 : 0.0)::Float64
end
Run Code Online (Sandbox Code Playgroud)
既然我已经定义了这些功能,我就可以做到
@assert istrait(IsProduct{Rope})
@assert istrait(IsProduct{Paper})
Run Code Online (Sandbox Code Playgroud)
现在,如果我定义
function measurements(x::Rope)
(x.length)::Float64
end
function measurements(x::Paper)
(x.height,x.width)::Tuple{Float64,Float64}
end
Run Code Online (Sandbox Code Playgroud)
然后我就能做到
@assert istrait(IsProductWithMeasurement{Rope,Float64})
@assert istrait(IsProductWithMeasurement{Paper,Tuple{Float64,Float64}})
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好; 这些运行没有错误.现在,我想要做的是编写如下函数:
@traitfn function get_measurements{X,M;IsProductWithMeasurement{X,M}}(similar_items::Array{X,1})
all_measurements = Array{M,1}(length(similar_items))
for i in eachindex(similar_items)
all_measurements[i] = measurements(similar_items[i])::M
end
all_measurements::Array{M,1}
end
Run Code Online (Sandbox Code Playgroud)
一般来说,这个函数是一个例子"我想要使用这样一个事实:作为程序员,我知道BaseType总是关联AssociatedType到帮助编译器进行类型推断.我知道每当我执行某项任务时[在这种情况,get_measurements但一般来说这可以在一堆案例中工作]然后我希望编译器以一致的图案方式推断出该函数的输出类型."
也就是说,例如
do_something_that_makes_arrays_of_assoc_type(x::BaseType)
Run Code Online (Sandbox Code Playgroud)
总是会吐出Array{AssociatedType},并
do_something_that_makes_tuples(x::BaseType)
Run Code Online (Sandbox Code Playgroud)
总会吐出来的Tuple{Int64,BaseType,AssociatedType}.
并且,一对这样的关系适用于所有对<BaseType,AssociatedType>; 例如,if BatmanType是RobinType与之关联SupermanType的基本类型,并且LexLutherType是始终关联的基本类型
do_something_that_makes_tuple(x::BatManType)
Run Code Online (Sandbox Code Playgroud)
将始终输出Tuple{Int64,BatmanType,RobinType},和
do_something_that_makes_tuple(x::SuperManType)
Run Code Online (Sandbox Code Playgroud)
将永远输出Tuple{Int64,SupermanType,LexLutherType}.
所以,我理解这种关系,我希望编译器为了速度而理解它.
现在,回到功能示例.如果这是有道理的,你会意识到虽然我给出的函数定义作为一个例子是"正确的",因为它满足这种关系并且编译,它是不可调用的,因为编译器不理解之间的关系X而且M,即使我这样做.特别是,由于M没有出现在方法签名中,因此Julia无法在函数上进行调度.
到目前为止,我唯一想要解决这个问题的方法是创建一种解决方法,我可以动态"计算"相关的类型,我仍然可以使用方法分派来完成这个计算.考虑:
function get_measurement_type_of_product(x::Rope)
Float64
end
function get_measurement_type_of_product(x::Paper)
Tuple{Float64,Float64}
end
@traitfn function get_measurements{X;IsProduct{X}}(similar_items::Array{X,1})
M = get_measurement_type_of_product(similar_items[1]::X)
all_measurements = Array{M,1}(length(similar_items))
for i in eachindex(similar_items)
all_measurements[i] = measurements(similar_items[i])::M
end
all_measurements::Array{M,1}
end
Run Code Online (Sandbox Code Playgroud)
然后这确实编译并且可以调用:
julia> get_measurements(Array{Rope,1}([Rope("blue",1.0,1.0,1.0),Rope("red",2.0,2.0,2.0)]))
2-element Array{Float64,1}:
1.0
2.0
Run Code Online (Sandbox Code Playgroud)
但是,这是不理想的,因为(一)我每次都要重新定义该地图,即使我觉得好像我已经告诉之间的关系的编译器X,并M通过使它们满足的特质,和(b)据我猜猜 - 也许这是错的; 我没有这个直接证据 --the编译器并不一定能够优化以及我想要的,因为之间的关系X,并M为"隐藏"的函数调用的返回值内.
最后一个想法:如果我有能力,我理想的做法是这样的:
@traitdef IsProduct{X} begin
isnew(X) -> Bool
coolness(X) -> Float64
? ! M s.t. measurements(X) -> M
end
Run Code Online (Sandbox Code Playgroud)
然后有一些方式来引用唯一见证存在关系的类型,例如
@traitfn function get_measurements{X;IsProduct{X},IsWitnessType{IsProduct{X},M}}(similar_items::Array{X,1})
all_measurements = Array{M,1}(length(similar_items))
for i in eachindex(similar_items)
all_measurements[i] = measurements(similar_items[i])::M
end
all_measurements::Array{M,1}
end
Run Code Online (Sandbox Code Playgroud)
因为这会以某种方式调度.
那么:我的具体问题是什么?我问,鉴于你可能在这一点上明白了我的目标
X和M,和那我该怎么办呢?我认为答案是
Traits.jl但我对这个想法持开放态度,事实上正确的答案是
我对表格的答案也非常满意
我不太热心(但仍然好奇地听到)这样的答案
我也认为这可能与输入Julia函数输出的问题有关,我认为它也在考虑之中,尽管我无法从这个问题中弄清楚这个问题的确切表示.
那么参数化函数呢?您可以使用参数化函数来指定类型关系,而不是尝试定义类型之间的关系。您可以定义一个函数get_measurements{T}(similar_items::Array{T}),并指定每个函数的预期输出类型T