将闭包数组减少为单个闭包

Reduce array of closures into single closure

假设我有一组闭包,它们都可以相互组合(即自同态,它们的输入和输出类型相同)。如何将这些闭包组合成一个闭包?

作为参考,我尝试设计如下内容。

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,就像 myClosures.reduce(STARTING) { a, b in b(a) }, 但这需要提供一个起始值,然后连续对其应用闭包。我不想将闭包应用到任何东西(目前),只是将私有闭包列表合成一个 public 闭包,以后可以应用。鉴于 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。如何做到这一点?这是处理闭包组合的更好方法吗?

编辑:我原来的回答误解了你的问题。但鉴于我原来的回答可能对未来的读者有用,我会把它留在底部。

您的 compose 功能即将实现! b(a) 无法编译,因为 MyClosure 没有占用另一个 MyClosureb(a) 调用 闭包 ("function application")。不是组成。既然 compose return 是一个闭包,为什么 return 不是一个闭包?典型的闭包在 Swift:

中看起来像这样
{ (param) in return doSomethingTo(param) }

所以让我们return那个!

return { (x) in return b(a(x)) }

这可以简化为:

{ b(a([=12=])) } // "return" can be omitted as well!

This page(除其他事项外)告诉您如何以及何时可以简化闭包语法。


原回答:

这里使用reduce是正确的选择。归约操作是组合,所以我们先写一个compose函数:

func compose<T>(_ x: @escaping (T) -> T, _ y: @escaping (T) -> T) -> (T) -> T {
    { y(x([=13=])) } // or { x(y([=13=])) } 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({ [=15=] }, compose)
}