传递一个闭包,该闭包将一个转义闭包转移到一个接受该类型闭包的函数

时间:2016-09-22 16:03:14

标签: ios swift closures y-combinator

在旧的快速世界(我相信2.0)我有以下Y-combinator实现

func Y<T, R>( f: (T -> R) -> (T -> R) ) -> (T -> R) {
    return { (t: T) -> R in
        return f(self.Y(f))(t)
    }
}

我会在其他地方调用Y-comb来创建一个递归闭包,如下所示:

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
let repeatClosure = self.Y {
    (f: () -> () ) -> (() -> ()) in
    return {
        if self.responses_received != responses_expected {
            dispatch_after(delayTime, dispatch_get_main_queue()) {                         
                // Resend 
                NSNotificationCenter.defaultCenter().
                    postNotificationName(sendData, 
                    object: nil, userInfo: dataToSend)

                f()
            }
        } else {
            print("Completed!")
            self.responses_received = 0
        }
    }
}

repeatClosure()

这个想法是,当'sendData'通知的观察者收到他的回复时,他会向包含我的Y-combinator和重复关闭的类发送通知。一旦'sendData'通知的观察者的所有实例都收到了他们的数据,

self.responses_received == responses_expected

将是真的,我们不会再次调用f()。

现在,我的问题是转换到Swift 3.0迫使我明确地声明'f'的类型为@escaping,在Y的定义上如此:

func Y<T, R>( _ f: @escaping ((T) -> R) -> ((T) -> R) ) -> ((T) -> R) {
    return { (t: T) -> R in
        return f(self.Y(f))(t)
    }
}

然后将我的重复闭包转换为相同的类型。哪个好,我理解@escaping和@noescape之间的区别以及为什么我的代码需要它。但是,在尝试构建时,我得到关于不匹配的类型的编译错误:

Cannot convert value of type '(@escaping () -> ()) -> (() -> ())' 
to expected argument type '(() -> ()) -> (() -> ())'

我创建了一个简单的示例闭包,只是为了测试,它给出了同样的错误:

let innerClosure = { (f: @escaping ()->()) -> (()->()) in
    return {}
}

let repeatClosure = self.Y(innerClosure)

以下没有问题:

let innerClosure = { (f: ()->()) -> (()->()) in
    return {}
}

let repeatClosure = self.Y(innerClosure)

我从fixit获得强制转换为类型的建议,没有@escaping标记。这编译,但感觉不对,我实际上没有测试该转换是否实际上在运行时工作。

我在这里缺少什么?

2 个答案:

答案 0 :(得分:1)

您的func Y<T, R>(_ f: @escaping (@escaping (T) -> R) -> ((T) -> R)) -> ((T) -> R) 函数应具有以下签名:

Y

因为它接受一个转义函数,它本身需要一个转义函数。

当您致电self.Y { (f: @escaping () -> ()) -> (() -> ()) in 时,闭包应以:

开头
@escaping

请注意,此Y对应于@escaping签名中转义的第二个。这个导致编译错误的table_headers = $("#careerStats table thead tr th"); var A = table_headers.map(function() {return this.textContent;}).get(); 不匹配。

其余大部分应该自行解决(一旦你将Dispatch和NSNotificationCenter调用更新到Swift 3)。

答案 1 :(得分:0)

我在操场上有这个代码,它构建没有任何问题:

class Foo {
  func Y<T,R>(_ f: @escaping ((T) -> R) -> ((T) -> R) ) -> ((T) -> R) {
    return { (t: T) -> R in
      return f(self.Y(f))(t)
    }
  }

  func test() {
    let innerClosure = { (f: ()->()) -> (()->()) in
      print("test")
      return {}
    }

    let repeatClosure = self.Y(innerClosure)
    repeatClosure()
  }
}

Foo().test() // prints "test"

你可能想要清理你的构建并重新尝试构建,因为我没有在我的操场上得到那个fixit建议。