Vermaji
Vermaji

Reputation: 75

How to create higher order functions in Swift?

I have come across the array forEach function that is a higher order function and it takes only one parameter, i.e., a closure. Now this closure internally loops through all the elements of the array one by one but does not return anything. The implementation of the closure is left to the choice of the user.

I have a custom class MyClass that has a private variable inside it num and a public function setNum(num: Int) to set the value of that private variable from outside. I am just trying to create a similar function factorial inside my custom class that takes only one parameter, i.e., a closure. However, I have to manually call the closure inside factorial, pass the value of num as a parameter to the closure.

Is there a way that the closure can act on num without having passed it as a parameter? Basically I am just trying to replicate the array forEach function. Syntax of array forEach is:

array.forEach(body: (Int) -> Void) -> Void)

Implementation:

arr1.forEach { print($0) }

My code is as below:

import Foundation

public class MyClass {
    private var factorialNumber: Double = 0
    internal static var instance: MyClass?

    public func setFactorialNumber(number value: Double) {
        factorialNumber = value
    }

    public func factorial(body closure: (String?) -> Void) -> Void {
        var outputString: String?
        var result: Double = 1

        if factorialNumber <= 0 {
            outputString = nil
        } else {
            outputString = ""
            while(factorialNumber >= 1) {
                if factorialNumber == 1 {
                    outputString = outputString! +  "\(factorialNumber) = \(result)"
                    break
                } else {
                    outputString = outputString! + "\(factorialNumber) x "
                }
                result = result * factorialNumber
                factorialNumber -= 1
            }
        }

        // Finally closure call
        closure(outputString)
    }

    private init() {}

    public static func getInstance() -> MyClass {
        if self.instance == nil {
            self.instance = MyClass()
        }
        return self.instance!
    }
}

And here is how I have to call my function to calculate the factorial:

var obj1 = MyClass.getInstance()

obj1.setFactorialNumber(number: 5)
obj1.factorial{ (result) in
    print(result ?? "Factorial Result is Nil")
}

Please note that I have to pass a parameter result inside my closure to get the result of factorial.

Upvotes: 0

Views: 2680

Answers (1)

matt
matt

Reputation: 535989

Is there a way that the closure can act on num without having passed it as a parameter? Basically I am just trying to replicate the array forEach function ... [And, in your comment:] All I am trying to do is learn how to create higher order functions like array.forEach.

It's hard to understand what you think you're after, but taking you at your word, let's write forEach. Here we go:

extension Sequence {
    func myForEach(f: (Element) -> ()) {
        for e in self {
            f(e)
        }
    }
}

Let's test it:

[1,2,3].myForEach { print($0) } // prints 1, then 2, then 3

We've done it! We wrote a higher-order function that acts exactly like forEach. So this must be how forEach actually works, more or less.

You can see from the example that it makes no sense to ask not to have to pass a parameter into the function that our forEach takes as a parameter. That is exactly what we must be able to do in order for that function to have an element to operate on.

Upvotes: 3

Related Questions