Swift 3 Parallel for/map Loop - swift

There's quite a few threads on this however Using Grand Central Dispatch in Swift to parallelize and speed up “for" loops? uses Swift <3.0 code and I can't get the equivalent to work in 3 (see code). Process Array in parallel using GCD uses pointers and it gets a bit ugly so I'm going to assert right here that I'm looking for the nice Swift 3 way to do it (as efficiently as possible of course). I also heard groups are slow (?) maybe someone can confirm that. I couldn't get groups to work either.
Here is my implementation of a striding parallel map function (in an extension of Array). It want's to execute on the global queue so as to not block the UI. It may be that the concurrent bit doesn't need to be in the scope, only the remainder loop.
extension Array {
func parallelMap<R>(striding n: Int, f: #escaping (Element) -> R, completion: #escaping ([R]) -> ()) {
let N = self.count
var res = [R?](repeating: nil, count: self.count)
DispatchQueue.global(qos: .userInitiated).async {
DispatchQueue.concurrentPerform(iterations: N/n) {k in
for i in (k * n)..<((k + 1) * n) {
res[i] = f(self[i]) //Error 1 here
}
}
//remainder loop
for i in (N - (N % n))..<N {
res[i] = f(self[i])
}
DispatchQueue.main.sync { //But it will pause on this line.
print("\nPlease work!\n") //This doesn't execute either.
completion(unwrap(res)!) //Error 2 here, or rather "not here"
}
}
}
}
public func unwrap<T>(_ arr: Array<T?>) -> Array<T>? {
if (arr.contains{$0 == nil}) {
return nil
} else {
return arr.map{(x: T?) -> T in x!}
}
}
Error 1: our old friend EXC_BAD_ACCESS on the inner array assignment line about half the times I test it. I'm guessing this suggests a simultaneous access issue.
Error 2: completion never executes!
Error 3: errors go on forever, I'm sure this will happen once the above are fixed.
Finally: code for the fastest parallel (making sure it's as parallel as possible, I don't like the 'concurrent' in my code) map/for function possible. This is in addition to fixing my code.

Martin's original approach is still the right way to do this. Merging your approach with his and converting to Swift 3 is fairly straightforward (though I got rid of your optionals and just handled the memory by hand).
extension Array {
func parallelMap<R>(striding n: Int, f: #escaping (Element) -> R, completion: #escaping ([R]) -> ()) {
let N = self.count
let res = UnsafeMutablePointer<R>.allocate(capacity: N)
DispatchQueue.concurrentPerform(iterations: N/n) { k in
for i in (k * n)..<((k + 1) * n) {
res[i] = f(self[i])
}
}
for i in (N - (N % n))..<N {
res[i] = f(self[i])
}
let finalResult = Array<R>(UnsafeBufferPointer(start: res, count: N))
res.deallocate(capacity: N)
DispatchQueue.main.async {
completion(finalResult)
}
}
}
Martin's version avoids the extra copy because he has a "zero" value to initialize the array to. If you know your type has a trivial init(), you can avoid the extra copy:
protocol TriviallyInitializable {
init()
}
extension Array {
func parallelMap<R>(striding n: Int, f: #escaping (Element) -> R, completion: #escaping ([R]) -> ()) where R: TriviallyInitializable {
let N = self.count
var finalResult = Array<R>(repeating: R(), count: N)
finalResult.withUnsafeMutableBufferPointer { res in
DispatchQueue.concurrentPerform(iterations: N/n) { k in
for i in (k * n)..<((k + 1) * n) {
res[i] = f(self[i])
}
}
}
for i in (N - (N % n))..<N {
finalResult[i] = f(self[i])
}
DispatchQueue.main.async {
completion(finalResult)
}
}
}

Related

Get first mapped result from array

I have an array of functions like
let array = [(Int) -> T?, (Int) -> T?, (Int) -> T?,...]
I need to get first non nil T value from array and I want 1 iteration for this task (O(n) will be the worst complexity). Anybody has neat ideas without for loops?
As I mentioned in my comment, there's no ready-made way to do this in Swift, so you have to at least implement something that uses a for loop.
If you want appearances at the call-site to look functional and not use a for loop, you can make the function extend Array like so:
extension Array {
func firstNonNilResult<V, T>(value: V) -> T? where Element == (V) -> T? {
for element in self {
if let t = element(value) {
return t
}
}
return nil
}
}
var array = [(Int) -> String?]()
func f(_ i: Int) -> String? {
print("called f() with \(i)")
return nil
}
func g(_ i: Int) -> String? {
print("called g() with \(i)")
return i == 5 ? "found it" : nil
}
array.append(f)
array.append(g)
if let t = array.firstNonNilResult(value: 5) {
print(t)
}
which prints:
called f() with 5
called g() with 5
found it
Whether or not this has any real-world utility I can't say. I think it's specialized enough that an Array extension seems like overkill, but your question is interesting so this is at least a potential solution.

Swift running sum

I'd like a function runningSum on an array of numbers a (or any ordered collection of addable things) that returns an array of the same length where each element i is the sum of all elements in A up to an including i.
Examples:
runningSum([1,1,1,1,1,1]) -> [1,2,3,4,5,6]
runningSum([2,2,2,2,2,2]) -> [2,4,6,8,10,12]
runningSum([1,0,1,0,1,0]) -> [1,1,2,2,3,3]
runningSum([0,1,0,1,0,1]) -> [0,1,1,2,2,3]
I can do this with a for loop, or whatever. Is there a more functional option? It's a little like a reduce, except that it builds a result array that has all the intermediate values.
Even more general would be to have a function that takes any sequence and provides a sequence that's the running total of the input sequence.
The general combinator you're looking for is often called scan, and can be defined (like all higher-order functions on lists) in terms of reduce:
extension Array {
func scan<T>(initial: T, _ f: (T, Element) -> T) -> [T] {
return self.reduce([initial], combine: { (listSoFar: [T], next: Element) -> [T] in
// because we seeded it with a non-empty
// list, it's easy to prove inductively
// that this unwrapping can't fail
let lastElement = listSoFar.last!
return listSoFar + [f(lastElement, next)]
})
}
}
(But I would suggest that that's not a very good implementation.)
This is a very useful general function, and it's a shame that it's not included in the standard library.
You can then generate your cumulative sum by specializing the starting value and operation:
let cumSum = els.scan(0, +)
And you can omit the zero-length case rather simply:
let cumSumTail = els.scan(0, +).dropFirst()
Swift 4
The general sequence case
Citing the OP:
Even more general would be to have a function that takes any sequence
and provides a sequence that's the running total of the input
sequence.
Consider some arbitrary sequence (conforming to Sequence), say
var seq = 1... // 1, 2, 3, ... (CountablePartialRangeFrom)
To create another sequence which is the (lazy) running sum over seq, you can make use of the global sequence(state:next:) function:
var runningSumSequence =
sequence(state: (sum: 0, it: seq.makeIterator())) { state -> Int? in
if let val = state.it.next() {
defer { state.sum += val }
return val + state.sum
}
else { return nil }
}
// Consume and print accumulated values less than 100
while let accumulatedSum = runningSumSequence.next(),
accumulatedSum < 100 { print(accumulatedSum) }
// 1 3 6 10 15 21 28 36 45 55 66 78 91
// Consume and print next
print(runningSumSequence.next() ?? -1) // 120
// ...
If we'd like (for the joy of it), we could condense the closure to sequence(state:next:) above somewhat:
var runningSumSequence =
sequence(state: (sum: 0, it: seq.makeIterator())) {
(state: inout (sum: Int, it: AnyIterator<Int>)) -> Int? in
state.it.next().map { (state.sum + $0, state.sum += $0).0 }
}
However, type inference tends to break (still some open bugs, perhaps?) for these single-line returns of sequence(state:next:), forcing us to explicitly specify the type of state, hence the gritty ... in in the closure.
Alternatively: custom sequence accumulator
protocol Accumulatable {
static func +(lhs: Self, rhs: Self) -> Self
}
extension Int : Accumulatable {}
struct AccumulateSequence<T: Sequence>: Sequence, IteratorProtocol
where T.Element: Accumulatable {
var iterator: T.Iterator
var accumulatedValue: T.Element?
init(_ sequence: T) {
self.iterator = sequence.makeIterator()
}
mutating func next() -> T.Element? {
if let val = iterator.next() {
if accumulatedValue == nil {
accumulatedValue = val
}
else { defer { accumulatedValue = accumulatedValue! + val } }
return accumulatedValue
}
return nil
}
}
var accumulator = AccumulateSequence(1...)
// Consume and print accumulated values less than 100
while let accumulatedSum = accumulator.next(),
accumulatedSum < 100 { print(accumulatedSum) }
// 1 3 6 10 15 21 28 36 45 55 66 78 91
The specific array case: using reduce(into:_:)
As of Swift 4, we can use reduce(into:_:) to accumulate the running sum into an array.
let runningSum = arr
.reduce(into: []) { $0.append(($0.last ?? 0) + $1) }
// [2, 4, 6, 8, 10, 12]
By using reduce(into:_:), the [Int] accumulator will not be copied in subsequent reduce iterations; citing the Language reference:
This method is preferred over reduce(_:_:) for efficiency when the
result is a copy-on-write type, for example an Array or a
Dictionary.
See also the implementation of reduce(into:_:), noting that the accumulator is provided as an inout parameter to the supplied closure.
However, each iteration will still result in an append(_:) call on the accumulator array; amortized O(1) averaged over many invocations, but still an arguably unnecessary overhead here as we know the final size of the accumulator.
Because arrays increase their allocated capacity using an exponential
strategy, appending a single element to an array is an O(1) operation
when averaged over many calls to the append(_:) method. When an array
has additional capacity and is not sharing its storage with another
instance, appending an element is O(1). When an array needs to
reallocate storage before appending or its storage is shared with
another copy, appending is O(n), where n is the length of the array.
Thus, knowing the final size of the accumulator, we could explicitly reserve such a capacity for it using reserveCapacity(_:) (as is done e.g. for the native implementation of map(_:))
let runningSum = arr
.reduce(into: [Int]()) { (sums, element) in
if let sum = sums.last {
sums.append(sum + element)
}
else {
sums.reserveCapacity(arr.count)
sums.append(element)
}
} // [2, 4, 6, 8, 10, 12]
For the joy of it, condensed:
let runningSum = arr
.reduce(into: []) {
$0.append(($0.last ?? ($0.reserveCapacity(arr.count), 0).1) + $1)
} // [2, 4, 6, 8, 10, 12]
Swift 3: Using enumerated() for subsequent calls to reduce
Another Swift 3 alternative (with an overhead ...) is using enumerated().map in combination with reduce within each element mapping:
func runningSum(_ arr: [Int]) -> [Int] {
return arr.enumerated().map { arr.prefix($0).reduce($1, +) }
} /* thanks #Hamish for improvement! */
let arr = [2, 2, 2, 2, 2, 2]
print(runningSum(arr)) // [2, 4, 6, 8, 10, 12]
The upside is you wont have to use an array as the collector in a single reduce (instead repeatedly calling reduce).
Just for fun: The running sum as a one-liner:
let arr = [1, 2, 3, 4]
let rs = arr.map({ () -> (Int) -> Int in var s = 0; return { (s += $0, s).1 } }())
print(rs) // [1, 3, 6, 10]
It does the same as the (updated) code in JAL's answer, in particular,
no intermediate arrays are generated.
The sum variable is captured in an immediately-evaluated closure returning the transformation.
If you just want it to work for Int, you can use this:
func runningSum(array: [Int]) -> [Int] {
return array.reduce([], combine: { (sums, element) in
return sums + [element + (sums.last ?? 0)]
})
}
If you want it to be generic over the element type, you have to do a lot of extra work declaring the various number types to conform to a custom protocol that provides a zero element, and (if you want it generic over both floating point and integer types) an addition operation, because Swift doesn't do that already. (A future version of Swift may fix this problem.)
Assuming an array of Ints, sounds like you can use map to manipulate the input:
let arr = [0,1,0,1,0,1]
var sum = 0
let val = arr.map { (sum += $0, sum).1 }
print(val) // "[0, 1, 1, 2, 2, 3]\n"
I'll keep working on a solution that doesn't use an external variable.
I thought I'd be cool to extend Sequence with a generic scan function as is suggested in the great first answer.
Given this extension, you can get the running sum of an array like this: [1,2,3].scan(0, +)
But you can also get other interesting things…
Running product: array.scan(1, *)
Running max: array.scan(Int.min, max)
Running min: array.scan(Int.max, min)
Because the implementation is a function on Sequence and returns a Sequence, you can chain it together with other sequence functions. It is efficient, having linear running time.
Here's the extension…
extension Sequence {
func scan<Result>(_ initialResult: Result, _ nextPartialResult: #escaping (Result, Self.Element) -> Result) -> ScanSequence<Self, Result> {
return ScanSequence(initialResult: initialResult, underlying: self, combine: nextPartialResult)
}
}
struct ScanSequence<Underlying: Sequence, Result>: Sequence {
let initialResult: Result
let underlying: Underlying
let combine: (Result, Underlying.Element) -> Result
typealias Iterator = ScanIterator<Underlying.Iterator, Result>
func makeIterator() -> Iterator {
return ScanIterator(previousResult: initialResult, underlying: underlying.makeIterator(), combine: combine)
}
var underestimatedCount: Int {
return underlying.underestimatedCount
}
}
struct ScanIterator<Underlying: IteratorProtocol, Result>: IteratorProtocol {
var previousResult: Result
var underlying: Underlying
let combine: (Result, Underlying.Element) -> Result
mutating func next() -> Result? {
guard let nextUnderlying = underlying.next() else {
return nil
}
previousResult = combine(previousResult, nextUnderlying)
return previousResult
}
}
One solution using reduce:
func runningSum(array: [Int]) -> [Int] {
return array.reduce([], combine: { (result: [Int], item: Int) -> [Int] in
if result.isEmpty {
return [item] //first item, just take the value
}
// otherwise take the previous value and append the new item
return result + [result.last! + item]
})
}
I'm very late to this party. The other answers have good explanations. But none of them have provided the initial result, in a generic way. This implementation is useful to me.
public extension Sequence {
/// A sequence of the partial results that `reduce` would employ.
func scan<Result>(
_ initialResult: Result,
_ nextPartialResult: #escaping (Result, Element) -> Result
) -> AnySequence<Result> {
var iterator = makeIterator()
return .init(
sequence(first: initialResult) { partialResult in
iterator.next().map {
nextPartialResult(partialResult, $0)
}
}
)
}
}
extension Sequence where Element: AdditiveArithmetic & ExpressibleByIntegerLiteral {
var runningSum: AnySequence<Element> { scan(0, +).dropFirst() }
}

Sum of Fibonacci term using Functional Swift

I'm trying to learn functional Swift and started doing some exercises from Project Euler.
Even Fibonacci numbers
Problem 2
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Implemented a memoized Fibonacci function, as per WWDC advanced Swift videos:
func memoize<T:Hashable, U>( body: ((T)->U,T) -> U) -> (T)->U {
var memo = [T:U]()
var result: ((T)->U)!
result = { x in
if let q = memo[x] { return q }
let r = body(result,x)
memo[x] = r
return r
}
return result
}
let fibonacci = memoize { (fibonacci:Int->Double,n:Int) in n < 2 ? Double(n) : fibonacci(n-1) + fibonacci(n-2) }
and implemented a class that conforms to the Sequence protocol
class FibonacciSequence: SequenceType {
func generate() -> GeneratorOf<Double> {
var n = 0
return GeneratorOf<Double> { fibonacci(n++) }
}
subscript(n: Int) -> Double {
return fibonacci(n)
}
}
The first (non-functional) solution of the problem:
var fib = FibonacciSequence().generate()
var n:Double = 0
var sum:Double = 0
while n < Double(4_000_000) {
if n % 2 == 0 {
sum += n
}
n = fib.next()!
}
println(sum)
The second, more functional solution, using ExSwift for it's takeWhile function
let f = FibonacciSequence()
println((1...40).map { f[$0] }
.filter { $0 % 2 == 0 }
.takeWhile { $0 < 4_000_000 }
.reduce(0, combine: +))
I'd like to improve on this solution, because of the 1...40 range at the begging that's calculating too many terms for no reason. Ideally I'd like to be able to have some sort of infinite range, but at the same time only calculate the required terms that satisfy the condition in the takeWhile
Any suggestions ?
Here I generate the sequence that already stops once max value is reached.
Then you just need to reduce without filtering, just sum 0 when n is odd.
func fibonacciTo(max: Int) -> SequenceOf<Int> {
return SequenceOf { _ -> GeneratorOf<Int> in
var (a, b) = (1, 0)
return GeneratorOf {
(b, a) = (a, b + a)
if b > max { return nil }
return b
}
}
}
let sum = reduce(fibonacciTo(4_000_000), 0) {a, n in (n % 2 == 0) ? a + n : a }
As an alternative, if you wish to keep fibonacci a more general function you could extend SequenceOf with takeWhile and reduce1 obtaining something that resembles function composition:
extension SequenceOf {
func takeWhile(p: (T) -> Bool) -> SequenceOf<T> {
return SequenceOf { _ -> GeneratorOf<T> in
var generator = self.generate()
return GeneratorOf {
if let next = generator.next() {
return p(next) ? next : nil
}
return nil
}
}
}
// Reduce1 since name collision is not resolved
func reduce1<U>(initial: U, combine: (U, T) -> U) -> U {
return reduce(self, initial, combine)
}
}
func fibonacci() -> SequenceOf<Int> {
return SequenceOf { _ -> GeneratorOf<Int> in
var (a, b) = (1, 0)
return GeneratorOf {
(b, a) = (a, b + a)
return b
}
}
}
let sum2 = fibonacci()
.takeWhile({ $0 < 4_000_000 })
.reduce1(0) { a, n in (n % 2 == 0) ? a + n : a}
Hope this helps
There is a filter() function which takes a sequence as an argument:
func filter<S : SequenceType>(source: S, includeElement: (S.Generator.Element) -> Bool) -> [S.Generator.Element]
but since the return value is an array, this is not suited if you want
to work with an "infinite" sequence. But with
lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 })
you get an "infinite" sequence of the even Fibonacci numbers. You cannot
call the .takeWhile() method of ExSwift on that sequence because
.takeWhile() is only defined for struct SequenceOf and not for
general sequences. But
TakeWhileSequence(
lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),
{ $0 < 4_000_000 }
)
works and gives the sequence of all even Fibonacci numbers less than
4,000,000. Then
let sum = reduce(TakeWhileSequence(
lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),
{ $0 < 4_000_000 }), 0, +)
gives the intended result and computes only the "necessary"
Fibonacci numbers.
Note that there is no actual need to memoize the Fibonacci numbers
here because they are accessed sequentially. Also (as #Matteo
already noticed), all Fibonacci numbers are integers. So you could
define the sequence more simply as
struct FibonacciSequence : SequenceType {
func generate() -> GeneratorOf<Int> {
var current = 1
var next = 1
return GeneratorOf<Int>() {
let result = current
current = next
next += result
return result
};
}
}
and the above computation does still work.
You can get quite close to what you want by using Swift's lazy sequences. If you take your generator of fibonacci numbers (here's the one I'm using:)
var (a, b) = (1, 0)
var fibs = GeneratorOf<Int> {
(b, a) = (a, b + a)
return b
}
You can wrap it in lazy():
var (a, b) = (1, 0)
var fibs = lazy(
GeneratorOf<Int> {
(b, a) = (a, b + a)
return b
}
)
Which exposes it to filter() as a lazy function. This filter() returns:
LazySequence<FilterSequenceView<GeneratorOf<Int>>>
Now, to get your takeWhile() function, you'd need to extend LazySequence:
extension LazySequence {
func takeWhile(condition: S.Generator.Element -> Bool)
-> LazySequence<GeneratorOf<S.Generator.Element>> {
var gen = self.generate()
return lazy( GeneratorOf{ gen.next().flatMap{ condition($0) ? $0 : nil }})
}
}
So that it returns nil (stops the generator) if either the underlying sequence ends, or the condition isn't satisfied.
With all of that, your fibonacci sequence under a given number looks a lot like what you wanted:
fibs
.filter {$0 % 2 == 0}
.takeWhile {$0 < 100}
//2, 8, 34
But, because reduce isn't a method on LazySequence, you have to convert to an array:
fibs
.filter {$0 % 2 == 0}
.takeWhile {$0 < 100}.array
.reduce(0, combine: +)
//44
You could do a quick and dirty extension to LazySequence to get reduce():
extension LazySequence {
func reduce<U>(initial: U, combine: (U, S.Generator.Element) -> U) -> U {
var accu = initial
for element in self { accu = combine(accu, element) }
return accu
}
}
And you can write the final thing like this:
fibs
.filter {$0 % 2 == 0}
.takeWhile {$0 < 100}
.reduce(0, combine: +)
//44
All of those sequences get to persist in their laziness - fibs is infinite, so they wouldn't really work otherwise. In fact, nothing is calculated until reduce: it's all thunks until then.
In Swift 3.1, here's an iterator that generates Fibonacci numbers forever, and an infinite sequence derived from it:
class FibIterator : IteratorProtocol {
var (a, b) = (0, 1)
func next() -> Int? {
(a, b) = (b, a + b)
return a
}
}
let fibs = AnySequence{FibIterator()}
You can get the sum of the even-numbered terms under four million like this:
fibs.prefix{$0 < 4000000}.filter{$0 % 2 == 0}.reduce(0){$0 + $1}
Be warned that filter and map are strict by default, and will run forever on an infinite Sequence. In the example above, this doesn't matter since prefix returns only a finite number of values. You can call .lazy to get a lazy Sequence where filter and map will behave non-strictly. For example, here are the first 5 even Fibonacci numbers:
> print( Array(fibs.lazy.filter{$0 % 2 == 0}.prefix(5)) )
[2, 8, 34, 144, 610]

YCombinator not working in Swift

I am trying to create a lambda function as such to get a factorial function but this throws a segmentation fault and errors out. How do I get this working in Swift. Please look at this video for reference on what I am trying to do http://www.confreaks.com/videos/1287-rubyconf2012-y-not-adventures-in-functional-programming
typealias f = () -> ()
typealias g = (Int) -> (Int)
typealias F = Any -> g
let y = { (gen: Any) -> g in
(gen as F)(gen)
}
let fact = y({ (gen: Any) -> g in
{ (n: Int) -> Int in
if n == 0 {
return 1
} else {
return n * (gen as F)(gen)(n - 1)
}
}
})
fact(10)
There's a great post by xiliangchen that walks through creating a Y-combinator in Swift. (Technically, this isn't a Y-combinator, since it is explicitly recursive, but it largely does what you want.) Here's an example of that Y function (stripped of its generic specification for clarity):
typealias G = Int -> Int
func Y (f: G -> G) -> G {
return {
(i: Int) -> Int in
f(Y(f))(i)
}
}
let factorial = Y { (f: G) -> G in
{ (n: Int) -> Int in
if n == 0 {
return 1
} else {
return n * f(n - 1)
}
}
}
factorial(5) // 120
For more on Y-combinators, you can look at this terrific (long) piece by Mike Vanier.
(Note: Using Any is kind of a mess -- I'd recommend steering clear of it whenever you can, especially since you don't need it in this case.)
You can implement a real (without explicit recursion) Y combinator using a recursive type, without any unsafe tricks (credits to Rosetta Code):
struct RecursiveFunc<F> {
let o : RecursiveFunc<F> -> F
}
func Y<A, B>(f: (A -> B) -> A -> B) -> A -> B {
let r = RecursiveFunc<A -> B> { w in f { w.o(w)($0) } }
return r.o(r)
}
let factorial = Y { (f: Int -> Int) -> Int -> Int in
{ $0 <= 1 ? 1 : $0 * f($0-1) }
}
println(factorial(10))
Any doesn't really help because Any cannot represent function types.
Update: Starting in Xcode 6.1 beta 3, Any can represent function types, and your code compiles and works correctly.
This is an implementation in modern Swift that actually compiles under Swift 5.7. It has the proper modern closure syntax and declares as escaping the escaping closures.
import Foundation
struct RecursiveFunc<T> {
let o : (RecursiveFunc<T>) -> T
}
func Y<A, B>(f: #escaping (#escaping (A) -> B) -> (A) -> B) -> (A) -> B {
let r = RecursiveFunc<(A) -> B> { w in f { w.o(w)($0) } }
return r.o(r)
}
let fac = Y { (f: #escaping (Int) -> Int) in
{ $0 <= 1 ? 1 : $0 * f($0-1) }
}
func fact (_ n: Int) -> Int {
if n == 0 { return 1 }
else { return n * fact (n-1) }
}
print (fact(19))
print (fac (19))
NB: code pasted from a PlayGround

How to handle closure recursivity

Here's a very simple recursive function:
func lap (n: Int) -> Int {
if n == 0 { return 0 }
return lap (n - 1)
}
If I want to convert it as closure:
let lap = {
(n: Int) -> Int in
if n == 0 { return 0 }
return lap (n - 1)
}
I got a compiler error: "Variable used within its own initial value"
you can workaround it with two step assignment
var lap : (Int) -> Int!
lap = {
(n: Int) -> Int in
if n == 0 { return 0 }
return lap(n - 1)
}
or you can use Y combinator
func Y<T, R>( f: (T -> R) -> (T -> R) ) -> (T -> R) {
return { t in f(Y(f))(t) }
}
let lap = Y {
(f : Int -> Int) -> (Int -> Int) in
return { (n : Int) -> Int in return n == 0 ? 0 : f(n - 1) }
}
// with type inference
let lap2 = Y {
f in { n in n == 0 ? 0 : f(n - 1) }
}
This is a workaround of the memory leak problem that #zneak found (It doesn't have memory leak but captured the wrong value)
func f(n: Int) {
var f = Foo()
var lap: #objc_block (Int)->Int = { $0 }
var obj: NSObject = reinterpretCast(lap)
lap = {
[weak obj] (n: Int) -> Int in // unowned will cause crush
if n == 0 { return 0 }
println(f)
var lap2 : #objc_block (Int)->Int = reinterpretCast(obj)
return lap2 (n - 1)
}
lap(n)
}
for i in 0..<5 {
f(i)
}
class Foo {
init() {
println("init");
}
deinit {
println("deinit")
}
}
EDIT This has been resolved with Swift 2 using nested functions. Apple suggests this code:
func f(n: Int) {
func lap(n: Int) -> Int {
if n == 0 { return 0 }
print(n)
return lap(n - 1)
}
lap(n)
}
for i in 0..<1000000 { f(i) }
Although this is not obvious from the current example, so-called local functions capture the locals of the enclosing scope.
Using a location function does not leak, whereas a closure would. However, clearly, lap can't be reassigned in this case.
I received an email from Apple's Joe Groff stating that they still plan on making it possible to capture closures as weak and mutable variables at a later point. This does confirm, however, that there's no way to do it right now except with a local function.
Your current solution has a memory leak in it: lap's closure has a strong reference to itself, meaning that it cannot ever be released. This can easily be verified by launching the following program with the Leaks instrument attached:
import Foundation
func f(n: Int) {
var lap: (Int)->Int = { $0 }
lap = {
(n: Int) -> Int in
if n == 0 { return 0 }
println(n)
return lap (n - 1)
}
lap(n)
}
for i in 0..<1000000 {
f(i)
}
Unfortunately, as the explicit capture syntax cannot be applied to closure types (you get an error that says "'unowned' cannot be applied to non-class type '(Int) -> Int'"), there appears to be no easy way to achieve this without leaking. I filed a bug report about it.
Here's a response to my own question:
var lap: (Int)->Int = { $0 }
lap = {
(n: Int) -> Int in
if n == 0 { return 0 }
println(n)
return lap (n - 1)
}
What about this:
let lap = {(Void) -> ((Int) -> Int) in
func f(n: Int) -> Int {
print(n)
return n == 0 ? 0 : f(n - 1)
}
return f
}()
It's quite simple, I've just defined a recursive local function inside a closure which returns the function.
However, I have to say that the answer from #Bryan Chen about the Y combinator is awesome.
I had the same problem and was not statisfied with anything that was out there, so I created a library and made it available on GitHub.
Using this library (with Swift 3.0) your code would look like this:
let lap = Recursion<Int, Int> { (n, f) in
n == 0 ? 0 : f(n-1)
}.closure