Genhain
Genhain

Reputation: 1937

Chained generic type inferred closures in swift

I am struggling to conceptualise in my head how to create a generic interface or class which functions like so.

 functionOne {
    return "123"
 }
 .chainedFunction { string -> Int in
    return Int(string) + 456
 }
 .anotherChain {
    [NSNumber($0), String($0)]
 }
 .lastInTheChain {
     print("value 1: \($0[0])")
     print("value 2: \($0[1])")
 }

so for this to work it is essentially an array of functions that pipe its return value into the next function's parameter list.

assuming each function closure was named after the function it came from i.e

 functionOne(_ functionOne:(T) -> T) {}
 chainedFunction(_ chainedFunction:(T) -> T) {}

then you would then call them like so to make sure you pass the correct values through.

lastInTheChain(anotherChain(chainedFunction(functionOne())))

The part i struggly mostly with is the Generics part and whether type inference will work or not (this is a secondary concern, would just be nice if it worked)

Im also attempting to use protocols, and generic protocols in swift require the use of thunks here and there which is only compounding my confusion.

So anyone out there a tad more knowledgeable if you would not mind chipping in how i could do this or whether it is doable in the first place i would be most appreciative.

Upvotes: 0

Views: 249

Answers (1)

Alexander
Alexander

Reputation: 63167

functionOne needs to return something that has a chainedFunction instance method, which itself needs to return something that has an anotherChain instance method, and so on. For this, you need to create a type. I'll call it wrapper because I don't know your use case, but you should name it something more meaningful.

import Foundation

struct Wrapper<T> {
    let value: T

    // This replaces `function1`
    init(_ value: T) { self.value = value }

    func chainedFunction<R>(_ transform: (T) -> R) -> Wrapper<R> {
        return Wrapper<R>(transform(self.value))
    }

    func anotherChain<R>(_ transform: (T) -> R) -> Wrapper<R> {
        return Wrapper<R>(transform(self.value))
    }

    func lastInTheChain<R>(_ transform: (T) -> R) -> R {
        return transform(self.value)
    }
}

 Wrapper("123")
 .chainedFunction { string -> Int in
    return Int(string)! + 456
 }
 .anotherChain {
    [NSNumber(value: $0), String($0)]
 }
 .lastInTheChain {
     print("value 1: \($0[0])")
     print("value 2: \($0[1])")
 }

Terminology: this Wrapper type is called a functor, because it defines a map method (here called chainedFunction and anotherChain, which are equivalent functions in the example). Using map, a closure which can be used to transform T to R (transform) can be used to transform a Wrapper<T> into a Wrapper<R>.

Upvotes: 3

Related Questions