I've been trying to convert this block of code from Objective-C (taken from https://gist.github.com/mikeash/1254684) to Swift. I've used it successfully to repeat a block of code based on results from API calls. Is there a better method to do this in Swift?
dispatch_block_t recursiveBlockVehicle(void (^block)(dispatch_block_t recurse)) {
return ^{
block(recursiveBlockVehicle(block));
};
}
Any help is appreciated.
Here’s a straight translation of your obj-c version:
func recursiveBlockVehicle(block: @escaping (()->Void)->Void) -> ()->Void {
return { block(recursiveBlockVehicle(block: block)) }
}
// test usage
var i = 5
let block = recursiveBlockVehicle { recurse in
if i > 0 {
print("\(i--) ")
recurse()
}
else {
println("blastoff!")
}
}
block() // prints 5 4 3 2 1 blastoff!
(I’ve subbed out the dispatch_block_t
since it doesn’t feel necessary in the Swift version, but you can use it instead of ()->Void
instead if you prefer)
For the 1-parameter version, you can use generics rather than the obj-c id
approach, so it can create type-safe single-parameter recursive blocks:
func recursiveBlockVehicle<T>(block: @escaping (T, (T)->Void)->Void) -> (T)->Void {
return { param in block(param, recursiveBlockVehicle(block: block)) }
}
let block1: (Int)->Void = recursiveBlockVehicle { i, recurse in
if i > 0 {
print("\(i) ")
recurse(i-1)
}
else {
print("blastoff!")
}
}
block1(5) // prints 5 4 3 2 1 blastoff!
(and Swift overloading means you don’t have to give them different names)
...and if you want your recursive function to return a value:
func recursiveBlockVehicle<T,U>(block: @escaping (T, (T)->U)->U) -> (T)->U {
return { (param: T)->U in block(param, recursiveBlockVehicle(block: block)) }
}
let factorial: (Int)->Int = recursiveBlockVehicle { i, factorial in
return i > 1 ? i*factorial(i-1) : 1
}
factorial(4) // returns 24
Note, this last one is really the only one you need – since T
and U
can be Void
, it serves the purposes of the zero-parameter non-returning one too, though you have to write your closures to take two parameters (the first one of which you can ignore, since it’ll be void), i.e.:
let block: ()->() = recursiveBlockVehicle { _, recurse in
If you like this sort of stuff you should check out the 2014 WWDC Advanced Swift video which as an example of a memoizing recursive function caller.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With