Julia 我如何分配与两种类型相关的特征,其中共同满足该特征的第二种类型由第一种唯一确定?
假设我有一个Julia特征,它与两种类型相关:一种类型是一种可能满足某种部分特征的“基本”类型,另一种是由基本类型唯一确定的关联类型。(也就是说,BaseType->AssociatedType之间的关系是一个函数。)总之,这些类型满足我感兴趣的复合特性 例如:Julia 我如何分配与两种类型相关的特征,其中共同满足该特征的第二种类型由第一种唯一确定?,julia,traits,Julia,Traits,假设我有一个Julia特征,它与两种类型相关:一种类型是一种可能满足某种部分特征的“基本”类型,另一种是由基本类型唯一确定的关联类型。(也就是说,BaseType->AssociatedType之间的关系是一个函数。)总之,这些类型满足我感兴趣的复合特性 例如: using Traits @traitdef IsProduct{X} begin isnew(X) -> Bool coolness(X) -> Float64 end @traitdef IsProd
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
下面是几个示例类型。请忽略示例的细节;它们只是指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
现在如果我定义
function measurements(x::Rope)
(x.length)::Float64
end
function measurements(x::Paper)
(x.height,x.width)::Tuple{Float64,Float64}
end
那我就可以了
@assert istrait(IsProductWithMeasurement{Rope,Float64})
@assert istrait(IsProductWithMeasurement{Paper,Tuple{Float64,Float64}})
到目前为止还不错;这些程序运行无误。现在,我要做的是编写如下函数:
@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
一般来说,此函数是“我想使用这样一个事实,即作为程序员,我知道BaseType
总是与AssociatedType
关联,以帮助编译器进行类型推断。我知道每当我做某项任务时[在本例中,get_measurements
,但一般来说,这可以在一系列情况下工作]然后我希望编译器以一致的模式方式推断该函数的输出类型。”
那就是,例如
do_something_that_makes_arrays_of_assoc_type(x::BaseType)
将始终吐出数组{AssociatedType}
,并且
do_something_that_makes_tuples(x::BaseType)
将始终吐出元组{Int64,BaseType,AssociatedType}
并且,一个这样的关系适用于所有对
;例如,如果BatmanType
是RobinType
关联的基本类型,SupermanType
是LexLutherType
始终关联的基本类型,则
do_something_that_makes_tuple(x::BatManType)
将始终输出元组{Int64,BatmanType,RobinType}
,和
do_something_that_makes_tuple(x::SuperManType)
将始终输出元组{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
然后,它确实编译并可调用:
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
但这并不理想,因为(a)我每次都必须重新定义这个映射,尽管我感觉好像我已经告诉了编译器X
和M
之间的关系,使它们满足特征,以及(b)据我猜测--可能这是错误的;我没有直接证据证明这一点----编译器不一定能够像我所希望的那样进行优化,因为X
和M
之间的关系“隐藏”在函数调用的返回值中
最后一个想法:如果我有能力,我理想的做法是:
@traitdef IsProduct{X} begin
isnew(X) -> Bool
coolness(X) -> Float64
∃ ! M s.t. measurements(X) -> M
end
然后以某种方式引用唯一见证存在关系的类型,例如
@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
因为这是可以分派的
那么:我的具体问题是什么?我想问的是,考虑到你现在大概已经明白我的目标是什么了
X
和M
抽象编程,
及Traits.jl
我还认为这可能与输入Julia的函数输出有关,我认为这也在考虑之中,尽管我还无法从这个问题的角度准确地解释这个问题。Whoa-Whoa-Whoa-Whoa。看起来你正在尝试重新实现所有的推断。jl.我不建议这样做t、 您真正想要完成什么?您的示例函数只需理解一下即可编写:
get_measurements(similous_items)=[measurements(item)for item in similous_items]
。狭义地说,我希望能够添加类型断言::Array{M}
在该表达式之后,假设::X
在方法签名中,并使该方法可调用,并进行编译,即使其知道M
是什么。但更一般地说,我希望能够使用符号M
执行任意操作,因为满足两个条件(a)符号X
已被赋予t的含义
@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