Breno Rios Ramos
Breno Rios Ramos

Reputation: 419

About generic currying in swift

I am stuck with the following problem:

Question 1 - Generic currying Create a protocol named Worker containing a function called perform, which takes in a function and returns a function; perform must have a default implementation. The function passed as a parameter should be named work, and takes as an argument an instance of the type conforming to the protocol and returns a generic type T. The output function is () -> T

struct Person {
    var name: String
    var age: Int
}

protocol Worker {
    func perform<A,T>(work: @escaping (A) -> (T)) -> () -> T
}

extension  Person: Worker {
    func perform<A, T>(work: @escaping (A) -> (T)) -> () -> T {
        return //execution of the function work
    }
}

The result of this should be something like this:

let person = Person(name: "Bob", age: 3)
let work = person.perform(work: {return "\(person.name) is working"})
print(type(of: work)) // () -> String
print(work()) // Bob is working

I am thinking that I have to return the execution of the work function passed as the parameter to my protocol function perform.

Am I thinking right? If I am, how could I do that?

I have already read about currying and generics, but I still can't figure this out.

EDIT 1:

I fixed the part about the default implementation, but I still can't figure it out how to return that closure.

struct Person: Worker {
    var name: String
    var age: Int
}

protocol Worker {
    func perform<A,T>(work: (A) -> (T)) -> () -> T
}

extension  Worker {
    func perform<A,T>(work: @escaping (A) -> T) -> () -> T {
        return {}
    }
}

I went back to my textbook and they give me the following example about currying a function:

func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
    return { x in { y in f(x, y) } }
}

So in my mind the return of my function should be:

  1. A closure with no arguments ()
  2. With a closure inside that receives an argument that is passed to work.

Like this:

return {() in {x in work(x)}}

The compiler gives me the following error:

Cannot convert return expression of type '() -> (A) -> T' to return type '() -> T'

I can't understand why that happens because the inner closure

{x in work(x)}

in my mind should return an value of type T, since it is the execution of the function work, but instead it returns an (A) -> T.

What am I missing?

Upvotes: 0

Views: 263

Answers (2)

倪竹逸
倪竹逸

Reputation: 1

and the perform method should be called like this:

person.perform(work: { p in "\(p.name) is working"})

Upvotes: 0

rob mayoff
rob mayoff

Reputation: 385960

The function passed as a parameter should be named work, and takes as an argument an instance of the type conforming to the protocol

Swift makes “the type conforming to the protocol” available as Self. So work's argument should be Self, not A. You don't need the A type at all.

protocol Worker {
    func perform<T>(work: @escaping (Self) -> T) -> () -> T
}

Given that signature, how can we write a default implementation?

  • We have to return a function that returns a T.
  • We can only make a T by calling work.
  • We have to pass a Self to work.
  • The only Self available is self.

So this is the only reasonable default implementation:

extension Worker {
    func perform<T>(work: @escaping (Self) -> T) -> () -> T {
        return { work(self) }
    }
}

Upvotes: 1

Related Questions