使用Julia中的Union类型进行操作

问题描述 投票:1回答:1

在Julia中,isimmutable函数应该可以告诉您对象何时不可变。但是,它不适用于类型,因此我想为此编写一个版本。根据我在其他地方找到的建议,一个好的开始是:

isimmtype(t::Type) = error("Type $t has not defined isimmtype")
isimmtype(t::DataType) = begin
    if !t.isconcretetype
        error("Abstract types are neither immutable nor mutable")
    else 
        return !t.mutable
    end
end

这很有用,可以回答很多但不是全部类型的问题。到目前为止,失败分为两类:

  1. 此模式适用的类型,但相对于Julia文档给出的答案是错误的。我发现的唯一示例是StringSymbol,它们都是不可变的,但是返回false。有关于此的错误报告,所以我的下意识解决方案是只为这些类型编写方法,以显式覆盖行为
  2. 此模式失败的类型。这些类型包括UnionUnionAll类型。两者似乎都有简单的解决方案。在UnionAll的情况下,我们可以使用类型变量的上限对类型的验证进行测试。对于Union{A,B},我们可以比较AB类型的可变性,并推论并集的可变性。

我继续将这些解决方案写成我认为是合理的类似特征的语法,并且部分起作用:

"""
    Mutability
The Mutability type is an abstract trait type with children Mutable, Immutable,
and UnknownMutability.
"""
abstract type Mutability end
struct Mutable <: Mutability end
struct Immutable <: Mutability end
struct UnknownMutability <: Mutability end
const MUT_TYPE = Mutable()
const IMM_TYPE = Immutable()
const UNK_TYPE = UnknownMutability()

"""
    mutability(obj)
Yields an object of type Mutable, Immutable, or UnknownMutability depending on
whether the given type object is mutable, immutable, or unknown.
"""
mutability(T::Type) = UNK_TYPE
isimmtype(T::Type) = IMM_TYPE === mutability(T)

mutability(T::DataType) = begin
    if !T.isconcretetype
        return UNK_TYPE
    elseif T.mutable
        return MUT_TYPE
    else
        return IMM_TYPE
    end
end
mutability(::Core.TypeofBottom) = UNK_TYPE
mutability(T::UnionAll) = mutability(T{T.var.ub})
mutability(::Type{String}) = IMM_TYPE
mutability(::Type{Symbol}) = IMM_TYPE
# This one causes problems:
mutability(::Type{Union{A,B}}) where {A,B} = begin
    let mA=mutability(A), mB=mutability(B)
        if mA === UNK_TYPE || mB === UNK_TYPE || mA !== mB
            return UNK_TYPE
        else
            return mA
        end
    end
end

如果定义了所有这些方法,但最后一个方法,则mutability函数将按我的预期工作,但Union{A,B}类型的一个例外是,它们始终标记为未知。但是,如果定义了最后一个方法,则它会与Int64之类的类型匹配,而没有在函数体中绑定B(即,在方法开头添加println(A, B)会导致错误,原因是B不会被定义)。我可以看到A <: Union{A,B}中存在歧义,但是如何在查询中明确匹配Union类型呢?在这种情况下,如何防止Type{Union{A,B}}Type{A}匹配?

另外:mutability函数是否还有其他标签错误的情况?

methods types julia dispatch union-types
1个回答
0
投票

自发布问题以来,我意识到的一个可能的答案是在默认方法中显式测试Union类型:

mutability(T::Type) = begin
    if typeof(T) !== Union
        return UNK_TYPE
    else
        let mA=mutability(T.a), mB=mutability(T.b)
            if mA === UNK_TYPE || mB === UNK_TYPE || mA !== mB
                return UNK_TYPE
            else
                return mA
            end
        end
    end
end

使用上述其他方法,可以正确进行以下所有测试:

map(k->k=>(mutability(k), isimmtype(k)), 
    [String, Symbol, Int64,
     Dict{Int64,String}, Array, Array{Int64,1},
     Tuple, Tuple{}, Tuple{Int64,String,Symbol},
     Union{String,Symbol}, Union{String,Array}, Union{Array,Dict}])

#12元素数组{Pair,1}:#字符串=>(Immutable(),true)#符号=>(Immutable(),true)#Int64 =>(Immutable(),true)#Dict {Int64,String} =>(Mutable(),假)#Array =>(Mutable(),false)#Array {Int64,1} =>(Mutable(),假)#元组=>(UnknownMutability(),假)#Tuple {} =>(Immutable(),true)#Tuple {Int64,String,Symbol} =>(Immutable(),true)#Union {String,Symbol} =>(Immutable(),true)#Union {String,Array} =>(UnknownMutability(),false)#Union {Dict,Array} =>(Mutable(),假)#

所有这些对我来说都是正确的。但是,我仍然想知道在Union上是否有其他明确匹配的解决方案,以及是否存在其他这些函数无法正确检测可变性的实例!

© www.soinside.com 2019 - 2024. All rights reserved.