我如何调度与两种类型有关的特征,其中第二种满足特征的类型由第一种特征决定?

时间:2016-02-24 22:19:28

标签: julia traits

假设我有一个与两种类型相关的朱莉娅特征:一种类型是一种"基础"可以满足某种部分特征的类型,另一种是由基本类型唯一确定的关联类型。 (也就是说,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

现在这里有几个示例类型。请忽略示例的细节;它们仅仅意味着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

由于我已经定义了这些功能,我可以做到

@assert istrait(IsProduct{Rope})
@assert istrait(IsProduct{Paper})

现在如果我定义

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

一般来说,这个函数是&#34;我想要使用这样一个事实:作为程序员,我知道BaseType始终与AssociatedType相关联以帮助具有类型推断的编译器。我知道每当我执行某项任务时[在这种情况下,get_measurements,但一般来说这可以在一堆案例中工作]然后我希望编译器以一致的图案方式推断该函数的输出类型。 &#34;

即,例如

do_something_that_makes_arrays_of_assoc_type(x::BaseType)

将始终吐出Array{AssociatedType}

do_something_that_makes_tuples(x::BaseType)

总是吐出Tuple{Int64,BaseType,AssociatedType}

AND,对于{em>所有对<BaseType,AssociatedType>,有一个这样的关系;例如如果BatmanType是与RobinType相关联的基本类型,SupermanTypeLexLutherType始终关联的基本类型,那么

do_something_that_makes_tuple(x::BatManType)

将始终输出Tuple{Int64,BatmanType,RobinType}

do_something_that_makes_tuple(x::SuperManType)

将始终输出Tuple{Int64,SupermanType,LexLutherType}

所以,理解这种关系,我希望编译器为了速度而理解它。

现在,回到功能示例。如果这是有道理的,你会意识到虽然我给出的函数定义是一个正确的&#39;在它满足这种关系并进行编译的意义上,它是不可调用的,因为编译器并不理解XM之间的关系,即使我这样做。特别是,由于M没有出现在方法签名中,因此Julia无法对该函数进行调度。

到目前为止,我唯一想要解决这个问题的方法是创建一种解决方法,我可以计算&#34;计算&#34;动态关联的类型,我仍然可以使用方法分派来完成这个计算。考虑:

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)我每次都必须重新定义这张地图,即使我觉得我已经已经告诉编译器XM之间的关系X让他们满足特质,(b)据我所知 - 也许这是错的;我没有这方面的直接证据 - 由于M@traitdef IsProduct{X} begin isnew(X) -> Bool coolness(X) -> Float64 ∃ ! M s.t. measurements(X) -> M end 之间的关系,编译器不一定能够优化我想要的优势是&#34;隐藏&#34;在函数调用的返回值内。

最后一个想法:如果我有能力,我理想做的事情是这样的:

@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

因为这会以某种方式调度。

那么:我的具体问题是什么?我问,鉴于你可能在这一点上明白我的目标是

  1. 让我的代码一般地展示这种结构,这样 我可以在很多情况下有效地重复这种设计模式 然后在MTraits.jl的高级摘要编程, 和
  2. 做(1)以这样的方式,编译器仍然可以最大限度地优化其能力/知道它们之间的关系 作为我的类型,编码员,我
  3. 那么,我应该怎么做呢?我认为答案是

    1. 使用{{1}}
    2. 做一些与你迄今为止所做的事情非常相似的事情
    3. 同样做____some聪明的事情,回答者会指出,
    4. 但我对这个想法持开放态度,事实上正确答案是

      1. 放弃这种方法,你以错误的方式思考问题
      2. 相反,请这样考虑:____ MWE ____
      3. 我对表格的答案也非常满意

        1. 你要求的是一个复杂的&#34; Julia的功能仍处于开发阶段,预计将包含在v0.x.y中,所以只需等待......
        2. 并且我不太热心(但仍然很想听)答案,例如

          1. 放弃朱莉娅;而是使用专为此类事物设计的语言________
          2. 我也认为这可能与输入朱莉娅的功能输出有关,我也认为它正在考虑之中,尽管我还没有弄清楚这个的确切表现就那个问题而言。

0 个答案:

没有答案