Возможно ли в Swift требовать, чтобы связанный тип соответствовал протоколу связанного типа? - PullRequest
3 голосов
/ 23 марта 2019

Я пытаюсь (по существу без причины) составить протокол, который описывает категории из теории категорий. Я пытался придумать что-то вроде этого.

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 объявлен протоколом. Можно ли как-то обойти эту проблему?

Edit:

Как указал Роб, код как таковой не имеет особого смысла. Протокол - это особый класс из ObjC и не тот тип, который описывает протоколы. Кроме того, не существует типа, который описывает все протоколы, потому что сами протоколы не могут соответствовать протоколам, поскольку они являются просто требованиями для других типов. То, что я искал, - это метатип, экземплярами которого были Any.Protocol, Sequence.Protocol и т. Д.

Я более подробно расскажу о том, какую конструкцию я пытаюсь описать.

Категория - это тип Object и тип гомоморфизмов между каждой парой экземпляров Object. Для двух экземпляров Object, A и B, тип гомоморфизмов обычно записывается как Hom (A, B), но я напишу Hom<A,B>, чтобы быть Swiftier. Категории тогда снабжены композицией, которая имеет подпись <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 не имеет зависимых типов. Невозможно описать категорию с типом объекта Int, поскольку нет способа иметь тип Hom<0,0>. Однако если требуется, чтобы тип Object являлся метатипом, то внезапно Hom<A,B> становится целесообразным для описания системы типов, потому что экземпляр метатипа - это тип (я думаю), который может быть универсальным параметром. Это то, что я пытался описать, установив Object: Protocol.

В 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>
}

но это также не стартер, потому что связанные типы не могут иметь общих параметров.

В моем случае использования у меня есть протокол, который описывает конечно порожденные абелевы группы и протокол, который описывает конечно порожденные унитальные кольца, и я хотел бы написать общий код, который не заботится о том, работает ли он с GroupHom<A,B> where A: AbelianGroup, B: Abelian Group , RingHom<A,B> where A: Ring, B: Ring или (A) -> B, поскольку каждый из них снабжен правильным видом композиции.

Может быть просто невозможно сделать это, что я был бы готов принять. Пожалуйста, дайте мне знать, если это достаточно отличается, чтобы его нужно было задать в качестве отдельного вопроса.

Ответы [ 2 ]

1 голос
/ 24 марта 2019
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 })

Я думаю, это направление, которое вы ищете.

1 голос
/ 23 марта 2019

дг

В swift вы не можете использовать связанный тип протокола в качестве ассоциированного типа, потому что не определено, что это за тип.

Связанный тип может использоваться только как ограничение для типов, например:

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
}

Причина, по которой ваш код не компилируется, заключается в том, что цель ассоциированного типа ограничена реализацией протокола ассоциированного типа (который не определен). Кто-то должен определить это, прежде чем использовать в качестве ограничения.

Подход к решению вашей проблемы может заключаться в создании общего класса. Давайте посмотрим на это:

protocol Category {
    associatedtype Object1: Equatable
}

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

}

Другим подходом может быть создание общего класса 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
}

Помните, что вы не можете использовать протоколы со связанными типами в качестве ограничения типа для связанного типа или в качестве типа для переменной или константы, сначала кто-то должен определить связанные типы.

Надеюсь, я вам помог.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...