Sorry for being unclear.
Consider this signature:
func map_any<A, B>(_ f: @escaping (A) -> B)
-> (any Sequence<A>)
-> any Sequence<B>
This map_any
isn't really a function. It is a function constructor with two generic (type) parameters: A
and B
. To use it to construct a function, you must âcallâ map_any
with two type arguments: one for A
and one for B
.
Swift doesn't have a syntax for directly âcallingâ the function constructor with just type arguments, but you can let it infer the type arguments by specifying the type you want the âcallâ to the function constructor to return. For example, you can âcallâ it like this:
let map_any_Int_String: (@escaping (_) -> _)
-> (any Sequence<Int>)
-> any Sequence<String>
= map_any
Above, Swift deduces that you want to pass Int
for the A
type parameter, and String
for the B
type parameter.
You can also let Swift infer some type arguments by passing a value for the f
parameter. For example:
let map_any_Int_String = map_any {
(i: Int) -> String in "\(i)"
}
Above, the function literal { (i: Int) -> String in "\(i)" }
is fully typed and so Swift can use it to infer A = Int
and B = String
.
So, in my prior post, when I said any Sequence<A>
is not generic, what I meant was that, when you âcallâ map_any
to construct a function, you get back a function that has no generic type parameters left; Swift âfilled inâ all the type parameters in order to construct the returned function.
Now consider this signature:
func map_some<A, B>(_ f: @escaping (A) -> B)
-> (some Sequence<A>)
-> any Sequence<B>
This use of some
is syntactic sugar for an anonymous type parameter. It could reasonably be desugared in one of two ways. One way to desugar it is like this:
func map_some<A, B, S>(_ f: @escaping (A) -> B)
-> (S)
-> any Sequence<B>
where S: Sequence, S.Element == A
This is a valid Swift type signature. Again, this is a function constructor, not a function. To make a function, you have to âcallâ it with three type arguments: one for A
, one for B
, and one for S
. Again, you can do that by specifying the type you want the âcallâ to return:
let map_some_Int_String: (@escaping (_) -> _)
-> (Array<Int>)
-> any Sequence<String>
= map_some
You can also âcallâ it if you pass a value for f
and then immediately pass a value for the anonymous parameter of type S
:
let strings: any Sequence<String> = map_some { "\($0)" }([2, 3, 5])
Above, Swift infers B = String
from the declared type of strings
, infers A = Int
from the literals 2
, 3
, and 5
, and infers S = Array<Int>
from the literal [2, 3, 5]
.
What you cannot do is âpartially applyâ map_some
by providing just types for the A
and B
parameters, while leaving S
unspecified. You cannot do this:
let map_some_Int_String: (@escaping (Int) -> String)
-> (_)
-> any Sequence<String>
= map_some
and you cannot do this:
let stringify: (some Sequence<Int>)
-> any Sequence<String>
= map_some { "\($0)" }
because Swift cannot infer a type for S
in either of those cases. This goes back to what I said in my first post: in Swift, generic functions (which are really function constructors) are not first-class. A function constructor can only be âcalledâ if Swift can infer types to pass for all of the type parameters. You cannot store a function constructor in a variable or pass one as an argument or return one from a function.