在Swift中是否可能要求关联类型符合关联类型的关联协议?

时间:2019-03-23 05:46:07

标签: swift swift-protocols associated-types

我正试图(基本上没有理由)制定一种从类别理论描述类别的协议。我试图提出这样的事情。

protocol Category {
    associatedtype Object: Protocol
}
protocol Hom {
    associatedtype C: Category
    associatedtype Source: C.Object
    associatedtype Target: C.Object
}

尤其是,我希望每个Hom类型都具有关联的类别C和关联的Source和Target类型,它们都是该类别中的对象。因此,我已将对象协议与每个类别相关联,并尝试使Hom的源和目标符合相应类别的对象协议。上面的代码无法使用

进行编译
Type 'Self.Source' constrained to non-protocol, non-class type 'Self.C.Object'

此错误至少不清楚,因为C.Object被声明为协议。有什么办法可以解决这个问题?

编辑:

正如Rob指出的那样,按原样编写代码没有太大意义。协议是ObjC中的特定类,不是描述协议的类型。此外,没有一种类型可以描述所有协议,因为协议本身不符合协议,因为它们只是对其他类型的要求。我正在寻找的是一个Any.Protocol,Sequence.Protocol等都是其实例的元类型。

我将详细介绍我要描述的结构。

类别是Object类型,并且在Object的每对实例之间具有同构类型。对于对象A和B的两个实例,同态的类型通常写为Hom(A,B),但我将Hom<A,B>写得更快一些。然后,类别将带有签名<A: Object, B: Object, C: Object>(_ f: Hom<A,B>, _ g: Hom<B,C>) -> Hom<A,C>的组成。

如果f是Hom<A,B>的实例,则A称为f的源或域,而B称为f的目标或共域。

然后,

类型本身就是一个类别,其中Object是所有类型的元类型,Hom<A,B> = (A) -> B

在Swift中分类很困难的主要原因是因为Swift没有依赖类型。因为无法拥有类型Hom<0,0>,所以无法描述对象类型为Int的类别。但是,如果要求对象类型是元类型,那么Hom<A,B>突然描述到类型系统是一件很有意义的事情,因为元类型的实例是一个类型(我认为),它可以是通用参数。 。这就是我试图通过设置“对象:协议”来描述的内容。

在Swift中,我真的很想描述

protocol Category {
    associatedtype Object: Metatype
    associatedtype Hom<A: Object, B: Object>
    func compose<A: Object, B: Object, C: Object>(_ f: Hom<A,B>, then g: Hom<B,C>) -> Hom<A,C>
}

但这也不是入门,因为关联的类型不能具有通用参数。

在我的用例中,我有一个描述有限生成的阿贝尔群的协议和一个描述有限生成的al环的协议,我很想写一个通用代码,该代码不关心它是否与{{1 }},GroupHom<A,B> where A: AbelianGroup, B: Abelian GroupRingHom<A,B> where A: Ring, B: Ring,因为它们每个都配备了正确的构图类型。

这样做可能是不可能的,我愿意接受。请让我知道这是否足够不同,应将其作为一个单独的问题进行询问。

2 个答案:

答案 0 :(得分:1)

dg

由于不能定义协议类型,因此不能快速使用协议associatedtype作为associatedType。

关联类型只能用作类型的约束,例如:

protocol Category {
    associatedtype Object1:Equatable
}

class Homs:Category{
    typealias Object1 = Int

    func sum(element:Object1){

        print(element+element)
    }
}

或者这样

protocol Category {
    associatedtype Object1: Equatable
}

protocol Homs {
    associatedtype Cat:Category
    associatedtype Source: Category where Source.Object1 == Cat.Object1
    associatedtype Target: Category where Target.Object1 == Cat.Object1
}

您的代码之所以不能编译的原因,是因为您的associatedtype Target被限制为实现协议的associatedType(未定义)。在用作约束之前,需要有人对其进行定义。

解决问题的一种方法可能是生成一个通用类。我们来看一下:

protocol Category {
    associatedtype Object1: Equatable
}

class Homs<Cat:Category,Source,Target> where Cat.Object1 == Source && Cat.Object1 == Target.Object1{

}

另一种方法可能是创建一个通用的Category类,并创建一个协议,其类型为Category类,category class,Source和Target符合Type:

class Category<T>{
}

protocol Homs {
    associatedtype ObjectType
    associatedtype Cat:Category<ObjectType>
    associatedtype Source where Source == ObjectType
    associatedtype Target where Target == ObjectType
}

类似于第二个示例:

protocol Category {
    associatedtype Object1: Equatable
}

protocol Homs {
    associatedtype Cat:Category
    associatedtype Source: Category where Source.Object1 == Cat.Object1
    associatedtype Target: Category where Target.Object1 == Cat.Object1
}

请记住,您不能将具有关联类型的协议用作关联类型的类型约束或变量或常量的类型,首先需要定义关联类型。

希望我能对您有所帮助。

答案 1 :(得分:1)

associatedtype Object: Protocol

此行并不代表您的意思。 Protocol不是Swift的一部分。它是ObjC运行时的一部分。 (这确实是一个令人困惑的导入。)

但是,即使确实如此,我也不相信这对您有帮助。重要的是要意识到,在Swift中,协议不符合协议,并且具有关联类型的协议不是类型。它们是类型的约束。这往往在各处蔓延,并使人们感到惊讶。

我怀疑您正在按照这些思路对事物进行建模(请注意,我的分类理论非常薄弱,因此,如果我在点上使用了错误的术语,请原谅我。)

我们想说的是,“一个类别包含一组对象,这些对象之间有一组箭头”。要到达那里,我想我们要从通用箭头开始:

protocol Arrow {
    associatedtype Source
    associatedtype Target
    var apply: (Source) -> Target { get }
}

同构是一个映射回其自身类型的箭头。

protocol Homomorphism: Arrow where Source == Target {
    typealias Object = Source
}

然后,我们可以表示一个类别:

protocol Category {
    associatedtype Object
    associatedtype Arrow: Homomorphism where Arrow.Object == Object
}

我想谈谈整数和函数的类别(我认为这是一个适当的类别)。所以首先我需要函数。

struct Function<Source, Target>: Arrow {
    let apply: (Source) -> Target
}

extension Function: Homomorphism where Source == Target {}

然后我可以声明类别。

struct Integers: Category {
    typealias Object = Int
    typealias Arrow = Function<Int, Int>
}

创建一个射影。

let increment = Function(apply: { (x: Int) in x + 1 })

我认为这是您正在寻找的方向。