2016-09-22 5 views
0

В старом быстром мире (2.0 я считаю) у меня был реализация следующих Y-комбинаторIssue пропускание замыкания, которое принимает ускользающее замыкание на функцию, которая принимает закрытие этого типа

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

Я бы назвал У-расческа других рекурсивное закрытия, например, так:

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- комбинатор и повторное замыкание. После того, как все экземпляры наблюдателя уведомления «SendData» получили свои данные,

self.responses_received == responses_expected 

бы быть правдой, и мы не будем называть п раз().

Теперь, мой вопрос заключается в том, что переход на 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 тег. Это компилируется, но он чувствует себя не так, и я на самом деле не проверял, действительно ли это действие будет работать во время выполнения.

Что мне здесь не хватает?

ответ

1

Вашей Y функции должна иметь следующую подпись:

func Y<T, R>(_ f: @escaping (@escaping (T) -> R) -> ((T) -> R)) -> ((T) -> R) 

, поскольку он принимает ускользающую функцию, которая сам нуждается в ускользающую функции.

При вызове Y, закрытие должно начинаться с:

self.Y { (f: @escaping() ->()) -> (() ->()) in 

заметить, что эта @escaping соответствует второй спасаясь в Y подписи. Это было несоответствие этому @escaping, что вызывало ошибку компилятора.

Большинство остальных должно сортировать себя (после того, как вы обновите вызовы Dispatch и NSNotificationCenter для Swift 3).

+0

A-ha, это было именно это, спасибо вам большое! – agreendev

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 предложения в моей детской площадке.