Вау снова! Это круто. Спасибо, что нашли время, чтобы написать это. Хотя это не так много строк кода, он представляет собой довольно значительный набор методов. Моя следующая задача - обдумать, как добавить в конвейер ленивый декартовой продукт ...

я есть список животных:

let animals = ["bear", "dog", "cat"]

И несколько способов преобразовать этот список:

typealias Transform = (String) -> [String]

let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural:    Transform = { [$0 + "s"] }
let double:    Transform = { [$0, $0] }

Немного в стороне, они аналогичны фильтру (выходы 0 или 1 элемент), карте (ровно 1 элемент) и плоской карте (более 1 элемента) соответственно, но определены единообразным образом, чтобы их можно было обрабатывать согласованно.

Я хочу создать ленивый итератор, который применяет массив этих преобразований к списку животных:

extension Array where Element == String {
  func transform(_ transforms: [Transform]) -> AnySequence<String> {

    return AnySequence<String> { () -> AnyIterator<String> in
      var iterator = self
        .lazy
        .flatMap(transforms[0])
        .flatMap(transforms[1])
        .flatMap(transforms[2])
        .makeIterator()

      return AnyIterator {
        return iterator.next()
      }
    }
  }
}

а это значит, я могу лениво делать:

let transformed = animals.transform([containsA, plural, double])

и проверить результат:

print(Array(transformed))

Я доволен, насколько это кратко, но ясно:

        .flatMap(transforms[0])
        .flatMap(transforms[1])
        .flatMap(transforms[2])

является проблемой, поскольку это означает, что функция преобразования будет работать только с массивом из 3 преобразований.

Редактировать: Я пытался:

  var lazyCollection = self.lazy
  for transform in transforms {
    lazyCollection = lazyCollection.flatMap(transform) //Error
  }
  var iterator = lazyCollection.makeIterator()

но в отмеченной строке я получаю ошибку:

Невозможно присвоить значение типа 'LazyCollection <FlattenCollection <LazyMapCollection <Array <String>, [String] >>>' для типа 'LazyCollection <Array <String >>'

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

Как я могу заставить функцию преобразования работать с массивом любого количества преобразований?

Одно WET решение для ограниченного числа преобразований будет (но YUK!)

  switch transforms.count {
  case 1:
    var iterator = self
      .lazy
      .flatMap(transforms[0])
      .makeIterator()
    return AnyIterator {
      return iterator.next()
    }
  case 2:
    var iterator = self
      .lazy
      .flatMap(transforms[0])
      .flatMap(transforms[1])
      .makeIterator()
    return AnyIterator {
      return iterator.next()
    }
  case 3:
    var iterator = self
      .lazy
      .flatMap(transforms[0])
      .flatMap(transforms[1])
      .flatMap(transforms[2])
      .makeIterator()
    return AnyIterator {
      return iterator.next()
    }
  default:
    fatalError(" Too many transforms!")
  }

Весь код:

let animals = ["bear", "dog", "cat"]

typealias Transform = (String) -> [String]

let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural:    Transform = { [$0 + "s"] }
let double:    Transform = { [$0, $0] }

extension Array where Element == String {
  func transform(_ transforms: [Transform]) -> AnySequence<String> {

    return AnySequence<String> { () -> AnyIterator<String> in
      var iterator = self
        .lazy
        .flatMap(transforms[0])
        .flatMap(transforms[1])
        .flatMap(transforms[2])
        .makeIterator()

      return AnyIterator {
        return iterator.next()
      }
    }
  }
}

let transformed = animals.transform([containsA, plural, double])

print(Array(transformed))

Ответы на вопрос(3)

Ваш ответ на вопрос