Я хочу перестроить какой-нибудь ленивый функционал Свифт. Чтобы объяснить ситуацию, я сначала объясню эквивалентную нетерпеливую ситуацию:
let numbers = 1...10
do {
print("==================== EAGER INLINE =============================")
/// We start with a series of transformation on an array:
let result
= numbers
.filter { $0 >= 5 } /// Drop numbers less than 5
.map { $0 * $0 } /// Square the numbers
.flatMap { [$0, $0+1] } /// Insert number+1 after each number
.filter { $0 % 3 != 0 } /// Drop multiples of 3
print(result)
/// [25, 26, 37, 49, 50, 64, 65, 82, 100, 101]
/// which is [5^2, 5^2+1, 6^2+1, 7^2, 7^2+1, 8^2, 8^2+1, 9^2+1, 10^2, 10^2+1]
/// (Note 6^2 and 9^2 missing because they are divisible by 3)
}
Мы можем преобразовать карту и flatMap в отдельную функцию:
extension Array where Element == Int {
func squareAndInsert() -> [Int] {
self
.map { $0 * $0 }
.flatMap { [$0, $0+1] }
}
}
do {
print("==================== EAGER REFACTOR =============================")
let result
= numbers
.filter { $0 >= 5 }
.squareAndInsert()
.filter { $0 % 3 != 0 }
print(result)
/// Gives exactly the same result: [25, 26, 37, 49, 50, 64, 65, 82, 100, 101]
}
Так что теперь мы будем повторить процесс но лениво. Первая строка:
do {
print("==================== LAZY INLINE =============================")
let result: some LazySequenceProtocol /// ": some LazySequenceprotocol" not strictly
/// required but without it my compiler grumbled about complexity so this is to give the
/// compiler a nudge in the right direction.
= numbers
.lazy /// Note the ".lazy" added here to make the array lazy.
.filter { $0 >= 5 }
.map { $0 * $0 }
.flatMap { [$0, $0+1] }
.filter { $0 % 3 != 0 }
print(result)
}
Что печатает: LazyFilterSequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<ClosedRange<Int>>, Int>, Array<Int>>>>(_base: Swift.FlattenSequence<Swift.LazyMapSequence<Swift.LazyMapSequence<Swift.LazyFilterSequence<Swift.ClosedRange<Swift.Int>>, Swift.Int>, Swift.Array<Swift.Int>>>(_base: Swift.LazyMapSequence<Swift.LazyMapSequence<Swift.LazyFilterSequence<Swift.ClosedRange<Swift.Int>>, Swift.Int>, Swift.Array<Swift.Int>>(_base: Swift.LazyMapSequence<Swift.LazyFilterSequence<Swift.ClosedRange<Swift.Int>>, Swift.Int>(_base: Swift.LazyFilterSequence<Swift.ClosedRange<Swift.Int>>(_base: ClosedRange(1...10), _predicate: (Function)), _transform: (Function)), _transform: (Function))), _predicate: (Function))
Yikes!
На первый взгляд выглядит довольно тревожно, но это правильно, потому что в отличие от нетерпеливого результата, который является массивом Ints, ленивый результат - итератор, который предоставит нам следующее число, когда мы его попросим, и это должно знать, как вернуться через все вызовы функций обратно к исходной последовательности , Вот что описывает этот тип. Очень хорошо, что теперь у нас есть ключевое слово "some", как и в прошлом, если бы мы хотели указать явный тип, нам нужно было бы набрать все вышеперечисленное, что немного загадочно !!
Чтобы увидеть список чисел, который нам нужен, чтобы заставить их вычислять, что мы можем сделать, поместив ленивую последовательность в массив: print(Array(result))
И это дает точно такой же результат, как и раньше: [25, 26, 37 , 49, 50, 64, 65, 82, 100, 101]
Итак, теперь вызов.
Я хочу реорганизовать ленивый код так же, как Я сделал нетерпеливый код.
squareAndInsert необходимо превратить LazySequenceProtocol<Int>
в some LazySequenceProtocol
, поэтому я пробую код ниже, но получаю различные ошибки компиляции:
extension LazySequenceProtocol where Element == Int {
func squareAndInsertLazy() -> some LazySequenceProtocol {
self
.map { $0 * $0 }
.flatMap { [$0, $0+1] }
}
}
do {
print("==================== LAZY REFACTOR =============================")
let result: some LazySequenceProtocol // Error 1: Property declares an opaque return type, but cannot infer the underlying type from its initializer expression
= numbers
.lazy
.filter { $0 >= 5 }
.squareAndInsertLazy() // Error 2: Value of type '[Int]' has no member 'squareAndInsertLazy'
.filter { $0 % 3 != 0 } // Error 3: Protocol type 'Any' cannot conform to 'LazySequenceProtocol' because only concrete types can conform to protocols
// Error 4: Value of type 'Any' has no member 'filter'
print(result)
}
Я думаю, что ошибка 1 будет вероятно go прочь, если я починю остальных. Интересно, если Ошибка 2 означает, что попытка передать ленивую последовательность в squareAndInsertLazy вызывает рвение, и это означает, что [Int] представляется в squareAndInsertLazy. Я не могу понять, как двигаться вперед.
Любая помощь приветствуется.