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

时间:2015-05-29 07:08:01

标签: function swift recursion functional-programming

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

func f()
{
    f()
}

然而,封闭不能指自己。例如:

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

产生以下错误:

Variable used within its own initial value

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

2 个答案:

答案 0 :(得分:15)

限制是两个对象无法同时实例化并相互引用。必须在另一个之前创建一个。您可以将函数标记为隐式解包可选。这样您可以使用nil初始化函数,但“保证”它稍后会有一个值。

var f: (Void -> Void)!

f = {
    f()
}

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

var f: (Void -> Void)

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

f = placeholder

答案 1 :(得分: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
}

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

g最初被分配了一个假功能(在通话时崩溃)。这样做是为了启用新值g的递归,其中g传递给f以及输入值T。重要的是要注意g中的g = { f(g, $0) }是指自身,而不是之前分配给它的假函数。因此,只要在((T) -> U)中引用了f参数,它就会引用g,而recursive { f, x in x != 10 ? f(x + 1) : "success" }(0) 则会引用自身。

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

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

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

更新:现在可以使用Swift 3预览6了!

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

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

会让我返回一个函数,一个逃逸的闭包在一个逃逸的闭包中!

@escaping

如果不是内部EXISTS属性,则上述代码无效。它还需要另一组括号,这使得它看起来比我在编写内联代码时所熟悉的更加冗长。