如何在 Swift 中创建 _inline_ 递归闭包?

How do I create an _inline_ recursive closure in Swift?

Swift 中的全局函数递归很简单。例如:

func f()
{
    f()
}

但是,闭包不能引用自身。例如:

var f: (Void -> Void) =
{
    f()
}

产生以下错误:

Variable used within its own initial value

有解决办法吗?如何创建递归闭包 inline?

有一个解决方法:

func unimplemented<T>() -> T
{
    fatalError()
}

func recursive<T, U>(f: (@escaping (((T) -> U), T) -> U)) -> ((T) -> U)
{
    var g: ((T) -> U) = { _ in unimplemented() }

    g = { f(g, [=10=]) }

    return g
}

recursive 是一个接受闭包 (((T) -> U), T) -> U 的函数,其中 ((T) -> U) 是对闭包的剥离版本的引用,而 return 是一个可用函数, g.

g 最初被分配了一个假函数(调用时崩溃)。这样做是为了启用新值 g 的递归,其中 g 与输入值 T 一起传递给 f。重要的是要注意 g = { f(g, [=24=]) } 中的 g 指的是它自己,而不是之前分配给它的假函数。因此,每当在 f 中引用 ((T) -> U) 参数时,它就是对 g 的引用,后者又引用了自身。

此函数允许内联递归,如下所示:

recursive { f, x in x != 10 ? f(x + 1) : "success" }(0)

该函数共循环11次,无需声明单个变量。

更新: 这现在适用于 Swift 3 预览 6!


就我个人而言,我发现这是一个相当优雅的解决方案,因为我觉得它可以将我的代码简化到最低限度。 Y 组合器方法,例如下面的方法

func recursive<T, U>(_ f: (@escaping (@escaping (T) -> U) -> ((T) -> U))) -> ((T) -> U)
{
    return { x in return f(recursive(f))(x) }
}

会让我 return 一个函数,一个在转义闭包中的转义闭包!

recursive { f in { x in x != 10 ? f(x + 1) : "success" } }(0)

如果没有内部 @escaping 属性,上面的代码将无效。它还需要另一组大括号,这使得它看起来比我在编写内联代码时习惯的更冗长。

限制是两个对象不能同时实例化,不能互相引用。必须先创建一个。您可以将函数标记为隐式解包可选。这样你用 nil 初始化函数,但是 "promise" 它稍后会有一个值。

var f: (Void -> Void)!

f = {
    f()
}

更新: 另一种没有隐式解包选项的方法:

var f: (Void -> Void)

var placeholder: (Void -> Void) = {
    f()
}

f = placeholder