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

Vat*_*not 16 recursion functional-programming function swift

在Swift中,递归对于全局函数来说是微不足道的.例如:

func f()
{
    f()
}
Run Code Online (Sandbox Code Playgroud)

但是,封闭不能指自己.例如:

var f: (Void -> Void) =
{
    f()
}
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

Variable used within its own initial value
Run Code Online (Sandbox Code Playgroud)

这有解决方法吗?如何在线创建递归闭包?

Kir*_*ins 15

由于两个对象无法在完全相同的时间进行,因此需要限制.一个人必须先创造另一个.您可以将函数标记为隐式解包可选.这样你初始化函数nil,但"保证"它将在以后有价值.

var f: (Void -> Void)!

f = {
    f()
}
Run Code Online (Sandbox Code Playgroud)

更新: 另一种方法可能是:

var f: (Void -> Void)

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

f = placeholder
Run Code Online (Sandbox Code Playgroud)

  • update 方法给出以下错误:`variable 'f'在初始化之前被闭包捕获 (2认同)

Vat*_*not 4

有一个解决方法:

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, $0) }

    return g
}
Run Code Online (Sandbox Code Playgroud)

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

g最初分配了一个假函数(调用时崩溃)。这样做是为了启用新值 的递归g,其中与输入值 一起g传递到。需要注意的是,in指的是它本身,而不是之前分配给它的伪函数。因此,每当在 中引用该参数时,它都是对 的引用,而后者又引用自身。 fTgg = { f(g, $0) }((T) -> U)fg

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

recursive { f, x in x != 10 ? f(x + 1) : "success" }(0)
Run Code Online (Sandbox Code Playgroud)

该函数总共重复 11 次,无需声明单个变量。

更新:现在可以与 Swift 3 预览版 6 一起使用!


就个人而言,我发现这是一个相当优雅的解决方案,因为我觉得它最大限度地简化了我的代码。AY 组合器方法,如下所示

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

会让我返回一个函数,一个转义闭包中的转义闭包!

recursive { f in { x in x != 10 ? f(x + 1) : "success" } }(0)
Run Code Online (Sandbox Code Playgroud)

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