【问题标题】:operating over the Union type in Julia在 Julia 中运行 Union 类型
【发布时间】:2019-10-13 15:04:18
【问题描述】:

在 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 not被定义)。我可以看到A &lt;: Union{A,B} 中存在歧义,但是如何明确匹配关于Union 类型的查询?在这种情况下,如何防止Type{Union{A,B}} 匹配Type{A}

另外:此mutability 函数是否存在其他错误标记的情况?

【问题讨论】:

    标签: methods types julia dispatch union-types


    【解决方案1】:

    发布问题后我意识到的一个可能答案是在默认方法中显式测试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}: # String => (Immutable(), true)
    # 符号 => (Immutable(), true)
    # Int64 => (Immutable(), true)
    # Dict{Int64,String} => (Mutable(), false)
    # 数组 => (Mutable(), false)
    # Array{Int64,1} => (Mutable(), false)
    # 元组 => (UnknownMutability(), false) # 元组{} => (Immutable(), true)
    # Tuple{Int64,String,Symbol} => (Immutable(), true)
    # Union{String, Symbol} => (Immutable(), true)
    # Union{String, Array} => (UnknownMutability(), false) # Union{Dict, Array} => (Mutable(), false) #

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

    【讨论】:

    【解决方案2】:

    只要您不关心 struct 类型需要对 isimmtype(::Type{TheStructType}) 进行显式定义,就可以:

    isimmtype(x::Type) = throw(ErrorException("isimmtype($x) is not defined"))
    
    function isimmtype(::Type{T}) where {T}
      if !T.isconcretetype
        throw(DomainError("Abstract types are neither immutable nor mutable"))
      else
        return !T.mutable
      end
    end
    
    isimmtype(::Type{Symbol}) = true
    isimmtype(::Type{String}) = true
    
    function isimmtype(x::Union)
        return all(isimmtype, Base.uniontypes(x))
    end
    
    isimmtype(x::UnionAll) = isimmtype(x{x.var.ub})   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-28
      • 1970-01-01
      相关资源
      最近更新 更多