Edit: Мой исходный ответ неправильно понял, в чем была ваша проблема. Но, поскольку мой исходный ответ может быть полезен будущим читателям, я оставлю его внизу.
Ваша функция compose
почти готова! b(a)
не компилируется, потому что MyClosure
не принимает другой MyClosure
. b(a)
- это вызов закрытия («приложение-функция»). не состав. Так как compose
возвращает закрытие, почему бы не вернуть закрытие? Типичное закрытие в Swift выглядит так:
{ (param) in return doSomethingTo(param) }
Итак, давайте вернем это!
return { (x) in return b(a(x)) }
Это можно упростить до:
{ b(a($0)) } // "return" can be omitted as well!
На этой странице (среди прочего) рассказывается, как и когда можно упростить синтаксис замыкания.
Исходный ответ:
Использование reduce
- правильный выбор. Операция сокращения: композиция , поэтому давайте сначала напишем функцию compose
:
func compose<T>(_ x: @escaping (T) -> T, _ y: @escaping (T) -> T) -> (T) -> T {
{ y(x($0)) } // or { x(y($0)) } if you want it the other way
}
Затем мы reduce
. Какая личность? Идентичность - это то, что имеет следующие свойства:
compose(identity, anything) == anything
compose(anything, identity) == anything
Какая функция это выполняет? Функция идентичности!
Получаем:
func reduceClosures<T>(_ closures: [(T) -> T]) -> (T) -> T {
closures.reduce({ $0 }, compose)
}