Общий рекурсив enum
Я могу легко выразить универсальное рекурсивное перечисление в Swift:
indirect enum Tree<T> {
case empty
case leaf(T)
case node(Tree, Tree)
}
Учитывая это, я могу создать несколько примеров деревьев Int
, скажем:
let exampleTrees: [Tree<Int>] = [
.empty,
.leaf(10),
.node(.node(.leaf(1), .leaf(2)), .node(.leaf(3), .leaf(4)))
]
Взаимная рекурсия
Перечисление Tree
является рекурсивным аналогично рекурсивной функции. Случаи empty
и leaf
завершают рекурсию, а node
- рекурсивный случай.
В рекурсивных функциях весьма обычно иметь пару взаимно рекурсивных функций. Глупый, но классический иллюстративный пример:
func isEven(_ x: Int) -> Bool {
return x == 0 ? true : isOdd(x-1)
}
func isOdd(_ x: Int) -> Bool {
return x == 0 ? false : isEven(x-1)
}
Аналогично, также можно объявить пару взаимно рекурсивных enum
s:
indirect enum AB {
case a
case b(CD)
}
indirect enum CD {
case c
case d(AB)
}
Учитывая это, я могу начать создавать рекурсивные значения. Вот несколько примеров ...
let exampleRecursives: [AB] = [
.a,
.b(.c),
.b(.d(.a)),
.b(.d(.b(.c)))
]
(Это, очевидно, все совершенно глупо и бесполезно - это просто для иллюстрации того, что происходит!)
Универсальный взаимно рекурсивный enum
Определения AB
и CD
имеют ограничительный характер, поскольку они не являются общими, и я бы хотел, чтобы они были общими:
indirect enum AB<T> {
case a
case b(T)
}
indirect enum CD<T> {
case c
case d(T)
}
Проблема
Учитывая, что у меня есть эти универсальные альтернативы, я хотел бы иметь возможность выразить тот же вид взаимно рекурсивного вложения, что и я, с неуниверсальными оригиналами. Мне нужно сказать Свифту, что тип AB<CD<AB<CD<AB<CD<AB<CD<AB<CD< …
, но бесконечно длинный.
Я попытался выразить это следующим образом:
typealias RecursiveABCD = AB<CD<RecursiveABCD>>
Это дает ошибку компиляции "Circular reference"
хотя.
Я тоже пробовал это:
typealias RecursiveAB = AB<RecursiveCD>
typealias RecursiveCD = CD<RecursiveAB>
Но опять же, ошибки компилятора с "Circular reference"
.
Работа вокруг
Обходным путем будет определение типа оболочки, например:
struct W {
init(_ x: AB<CD<W>>) {
self.x = x
}
let x: AB<CD<W>>
}
Если я сделаю это, я смогу создать примеры, например:
let exampleRecursives: [W] = [
W(.a),
W(.b(.c)),
W(.b(.d(W(.a)))),
W(.b(.d(W(.b(.c)))))
]
Похоже, это станет очень громоздким и неудобным в использовании.
Вопрос
Можно ли использовать рекурсивные обобщенные перечисления без использования оболочки?