I'm trying to write a variadic zip function that will take a function A... -> B
, and returns a function Functor<A>... -> Functor<B>
. I feel like I'm close, but am running into an error and I'm not sure if this is just a current limitation of the language, or if I'm doing something wrong:
struct Functor<A> {
let work: () -> A
func map<B>(_ transform: @escaping (A) -> B) -> Functor<B> {
Functor<B> { transform(work()) }
}
}
func zip<each Element>(_ functor: repeat Functor<each Element>) -> Functor<(repeat each Element)> {
Functor<(repeat each Element)> {
(repeat (each functor).work())
}
}
// So far so good
// Here comes trouble...
func zip<each Element, Result>(with transform: @escaping ((repeat each Element)) -> Result) -> (repeat Functor<each Element>) -> Functor<Result> {
func resultFunc(_ element: repeat Functor<each Element>) -> Functor<Result> {
zip(repeat each element).map(transform)
}
return resultFunc // Error: Pack expansion requires that 'each Element' and 'repeat each Element' have the same shape
}
To simplify the example I tried
let foo = resultFunc
And it's inferred to be of type
(repeat Functor<each Element>) -> Functor<Result>
which on the surface, seems to be exactly what I want, but when I explicitly specify the type to be the same as what's inferred
let foo: (repeat Functor<each Element>) -> Functor<Result> = resultFunc
// Error: Pack expansion requires that 'each Element' and 'repeat each Element' have the same shape
I get the same error.
Is this an inherent limitation of the language right now, or am I not specifying my types correctly? Any way to do what I'm wanting?
What I'm trying to avoid
func zip2<A, B, C>(
with transform: @escaping (A, B) -> C
) -> (Functor<A>, Functor<B>) -> Functor<C> {
{ zip2($0, $1).map(transform) }
}
func zip3<A, B, C, D>(
with transform: @escaping (A, B, C) -> D
) -> (Functor<A>, Functor<B>, Functor<C>) -> Functor<D> {
{ zip3($0, $1, $2).map(transform) }
}
// etc... up to Nth arity