Сократите количество закрытий до одинарных закрытий - PullRequest
0 голосов
/ 09 мая 2020

Предположим, у меня есть массив замыканий, которые все могут быть составлены друг с другом (т. Е. Эндоморфизмы, их типы ввода и вывода совпадают). Как я могу объединить эти замыкания в одно замыкание?

Для справки, я пытался создать что-то вроде следующего.

struct MyType {
    typealias MyClosure: (T) -> T
    private var myClosures: [MyClosure] = [ ... ]
    public var closure: MyClosure {
        get {
            return ? // somehow compose all of myClosures into a single closure here
        }
    }
}

Моей первой мыслью было использовать reduce, à la myClosures.reduce(STARTING) { a, b in b(a) }, но для этого необходимо указать начальное значение, а затем последовательно применить к нему замыкания. Я не хочу (пока) применять закрытие к чему-либо, а просто синтезирую частный список закрытий в одно закрытие publi c, которое можно применить позже. Учитывая способ определения reduce, я ожидаю, что это будет выглядеть примерно как

myClosures.reduce(identity) { a, b in compose(a, b) }

func identity(_ input: T) { return input }

func compose(a: MyClosure, b: MyClosure) -> MyClosure { return b(a) }

, но тип b(a) - T, а не (T) -> T. Как этого добиться? Это лучший способ закрыть композицию?

1 Ответ

0 голосов
/ 09 мая 2020

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)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...