Passing around generic functions

I believe you're looking for higher-rank types (rank-2 for your use case). Friendlier explanation here.

A nice name for this in Swift might be "generic function values" or "generic closures". It could look like this:

func foo(_ f: <T> (T) -> T) {
       //  ^~~~~~~~~~~~~~~ first-class generic closure
  f(1)
  f(2.0)
  f(3 as UInt8)
}
let identity: <T> (T) -> T = { $0 }
foo(identity)

I don't think this language feature is widely supported outside of Haskell, as it's known to complicate type inference.

Though it is possible to emulate rank-2 types by adding a level of indirection, like defining a protocol with a generic method (as you did), or a ~> trait with a polymorphic apply method in Scala.

// `Rank2Function` represents `<T> (T) -> T`.
protocol Rank2Function {
  static func callAsFunction<T>(_ input: T) -> T
                         // ^~~ higher-rank type parameters bound here
}
func foo<Fn: Rank2Function>(_ f: Fn.Type) {
  // `static func callAsFunction` sugar isn't supported yet, so we have to spell it out.
  f.callAsFunction(1)
  f.callAsFunction(2.0)
  f.callAsFunction("Hello")
}
12 Likes