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.
Related
I know that closures capture the values in a given environment. That is not my question. My question is how do I capture the return value of a closure. For example if I use a closure as a parameter like:
func myClosure(yourAge x: Int, completion: (Int) -> String) {
if x == 4 {
completion(x)
}
}
then say:
let answer = myClosure(yourAge: 4) { x in
return "You're just a baby"
}
The warning is:
Constant 'answer' inferred to have type '()', which may be unexpected
And I understand that warning. Pretty much answer will not be an answer at all. It will be Void or ()
Now if I make the entire function return a String such as:
func myClosure(yourAge x: Int, completion: (Int) -> String) -> String {
completion(x)
}
Then I can of course capture the result in a property:
let answer = myClosure(yourAge: 4) { x in
if x < 10 { return "You're just a baby"}
else {
return "You can play the game"
}
}
And maybe I just answered my own question here but is there no simple way to place the return value of a closure into a property or I am using this in an unintended way?
If you wanted to do this purely with a closure (and not a function that accepts a closure), you could do something like:
let myClosure: (Int) -> String = { age in
if age < 10 {
return "You're just a baby"
}
else {
return "You can play the game"
}
}
let answer = myClosure(4) // "You're just a baby"
I am trying to write or implement my own higher order function my way, but not able to write it.
In below code I tried to write filter.
var array : [String] = ["Sagar","Harshit","Parth","Gunja","Marmik","Sachin","Saurav"]
//Native filter function of Swift
array = array.filter { (name) -> Bool in
return name.prefix(1) == "S"
}
I implement below code, according to method signature of filter, but as I know , we can not write closure with return type(If possible then I don't know).
func filterArray(_ array : [String], completionHandler : (_ name : String) -> ()) -> (){
for (_, value) in array.enumerated(){
completionHandler(value)
}
}
self.filterArray(array) { (name) -> () in
if name.prefix(1) != "S"{
if let index = array.index(of: name){
array.remove(at: index)
}
}
}
My implementation working fine and filtering array. But I want to abstract logic of remove object from array.
Can we write our own higher order functions or not ?
If yes then please help to implement above one.
Thanks in advance.
And you can define a return type to a closure. You can find a working example below, but for this purpose I suggest using the Swift built in filter function which can provide the same solution and much faster.
var array : [String] = ["Sagar","Harshit","Parth","Gunja","Marmik","Sachin","Saurav"]
func filterArray(_ array : inout [String], condition: (_ name : String) -> Bool) -> (){
var filteredArray: [String] = []
for value in array {
if condition(value) {
filteredArray.append(value)
}
}
array = filteredArray
}
filterArray(&array) { (name) -> Bool in
return !name.hasPrefix("S")
}
print(array)
You can define your own higher order functions on collections.
There is a great session about collections where Soroush shows an example of writing your own higher order function extending a collection.
https://academy.realm.io/posts/try-swift-soroush-khanlou-sequence-collection/
// Swit built in filter
let numberOfAdmins = users.filter({ $0.isAdmin }).count // => fine
// Custom "filter"
let numberOfAdmins = users.count({ $0.isAdmin }) // => great
extension Sequence {
func count(_ shouldCount: (Iterator.Element) -> Bool) -> Int {
var count = 0
for element in self {
if shouldCount(element) {
count += 1
}
}
return count
}
}
I have this loop, decrementing an integer by division, in Swift 2.
for var i = 128; i >= 1 ; i = i/2 {
//do some thing
}
The C-style for loop is deprecated, so how can I convert this to Swift 3.0?
Quite general loops with a non-constant stride can be realized
with sequence:
for i in sequence(first: 128, next: { $0 >= 2 ? $0/2 : nil }) {
print(i)
}
Advantages: The loop variable i is a constant and its scope is
restricted to the loop body.
Possible disadvantages: The terminating condition must be adapted
(here: $0 >= 2 instead of i >= 1), and the loop is always executed
at least once, for the first value.
One could also write a wrapper which resembles the C-style for loop
more closely and does not have the listed disadvantages
(inspired by Erica Sadun: Stateful loops and sequences):
public func sequence<T>(first: T, while condition: #escaping (T)-> Bool, next: #escaping (T) -> T) -> UnfoldSequence<T, T> {
let nextState = { (state: inout T) -> T? in
guard condition(state) else { return nil }
defer { state = next(state) }
return state
}
return sequence(state: first, next: nextState)
}
and then use it as
for i in sequence(first: 128, while: { $0 >= 1 }, next: { $0 / 2 }) {
print(i)
}
MartinR's solution is very generic and useful and should be part of your toolbox.
Another approach is to rephrase what you want: the powers of two from 7 down to 0.
for i in (0...7).reversed().map({ 1 << $0 }) {
print(i)
}
I'll suggest that you should use a while loop to handle this scenario:
var i = 128
while i >= 1
{
// Do your stuff
i = i / 2
}
Another question asked, essentially, how to implement a take function which would return the first n elements of a sequence. My answer was:
struct TakeFromSequenceSequence<S:SequenceType> : SequenceType {
var limit : Int
var sequence : S
func generate() -> AnyGenerator<S.Generator.Element> {
var generator = sequence.generate()
var limit = self.limit
return anyGenerator {
guard limit > 0 else {
return nil
}
limit = limit - 1
return generator.next()
}
}
}
extension SequenceType {
func take(count:Int) -> TakeFromSequenceSequence<Self> {
return TakeFromSequenceSequence(limit: count, sequence: self)
}
}
but it seems like I ought to be able to use AnySequence and anyGenerator to do it all inline in my take function:
extension SequenceType {
func take(count:Int) -> AnySequence<Self.Generator.Element> {
// cannot invoke initializer for type 'AnySequence<_>' with an argument list of type '(() -> _)'
return AnySequence({
var generator = self.generate()
var limit = count
// cannot invoke 'anyGenerator' with an argument list of type '(() -> _)'
return anyGenerator({
guard limit > 0 else {
return nil
}
limit = limit - 1
return generator.next()
})
})
}
}
Unfortunately, this yields multiple typing errors, mostly (I think) because type inference is failing.
Anybody have any suggestions on how to get this (using AnySequence and anyGenerator inline) to work?
(The answer is now based on Swift 2.2/Xcode 7.3. A solution for Swift 2.1 can be found in the edit history.)
The type of the closure passed to the AnySequence init method
must be specified explicitly:
extension SequenceType {
func take(count:Int) -> AnySequence<Generator.Element> {
return AnySequence { () -> AnyGenerator<Generator.Element> in
var generator = self.generate()
var limit = count
return AnyGenerator {
guard limit > 0 else {
return nil
}
limit = limit - 1
return generator.next()
}
}
}
}
Note that the (redundant) Self. in Self.Generator.Element is omitted, otherwise it does not compile.
Example:
let sequence = [1,2,3,4,5].take(2)
print(Array(sequence)) // [1, 2]
print(Array(sequence)) // [1, 2]
Alternatively, the method can be defined as
extension SequenceType {
func take(count:Int) -> AnySequence<Generator.Element> {
var generator = self.generate()
var limit = count
return AnySequence {
return AnyGenerator {
guard limit > 0 else {
return nil
}
limit = limit - 1
return generator.next()
}
}
}
}
Now the closure passed to the AnySequence init method is a "single-expression closure" and the type is inferred by the compiler.
But – as David Berry noted – the created sequence then behaves differently, the generate() method cannot be called repeatedly
with identical results:
let sequenceX = [1,2,3,4,5].take(2)
print(Array(sequenceX)) // [1, 2]
print(Array(sequenceX)) // []
This is permitted behavior, as stated in the SequenceType protocol reference:
... It is not correct to assume that a sequence will either be
"consumable" and will resume iteration, or that a sequence is a
collection and will restart iteration from the first element. A
conforming sequence that is not a collection is allowed to produce an
arbitrary sequence of elements from the second generator.
So one can choose among these implementations, dependent on the desired behavior.
I am working with some piece of code found in Functional programming in Swift, but the book is not updated with Swift 2, and I am getting on error in the following code:
func insert<T: Hashable>(key: [T], trie: Trie<T>) -> Trie<T> {
if let (head, tail) = key.decompose {
if let nextTrie = trie.children[head] {
var newChildren = trie.children
newChildren[head] = insert(tail, trie: nextTrie)
return Trie(isElem: trie.isElem, children: newChildren)
} else {
var newChildren = trie.children
newChildren[head] = single(tail)
return Trie(isElem: trie.isElem, children: newChildren)
}
} else {
return Trie(isElem: true, children: trie.children)
}
}
func buildString(words: [String]) -> Trie<Character> {
return reduce(words, empty()) { trie, word in
insert([word], trie: trie)
}
}
Inside buildString I get this:
Cannot convert return expression of type Trie<String> to return type Trie<Character>
How can I fix this ?
Assuming that empty looks like this
func empty<T>() -> Trie<T> {
return Trie<T>()
}
change the buildString function to
func buildString(words: [String]) -> Trie<Character> {
return words.reduce(empty()) { trie, word in
insert(Array(word.characters), trie: trie)
}
}
Explanation
What you want in the first argument of insert is an array of Character instances which you get by calling Array(word.characters). Array(word) is the Swift 1.2 way and doesn't work in Swift 2 anymore. In addition, [word.characters] just creates an array with a single element (the string's character view) which is why it doesn't work as well.
Note that I also changed the global reduce function (Swift 1.2 way) to the instance method .reduce (Swift 2 way).