How do I rewrite zip function by the new "repeat each" syntax?

This is what I got so far.
I don't know how to express "the Dependencies of each MiddlewareReader should be the same"

extension MiddlewareReaderProtocol {
    public static func zip<each M: MiddlewareReaderProtocol, MOutput: MiddlewareProtocol>(
        _ readers: repeat each M,
        with map: @escaping @Sendable (repeat (each M).MiddlewareType) -> MOutput
    ) -> MiddlewareReader<M[0].Dependencies, MOutput> // Error: Array types are now written with the brackets around the element type
    where (repeat (M.Dependencies == M[0].Dependencies)) {
        MiddlewareReader { environment in
            map((repeat each readers).inject(environment))
        }
    }
}

original method

    public static func zip<M1: MiddlewareReaderProtocol, M2: MiddlewareReaderProtocol, M3: MiddlewareReaderProtocol, MOutput: MiddlewareProtocol>(
        _ reader1: M1,
        _ reader2: M2,
        _ reader3: M3,
        with map: @Sendable @escaping (M1.MiddlewareType, M2.MiddlewareType, M3.MiddlewareType) -> MOutput
    ) -> MiddlewareReader<M1.Dependencies, MOutput> where M1.Dependencies == M2.Dependencies, M1.Dependencies == M3.Dependencies {
        MiddlewareReader { environment in
            map(reader1.inject(environment), reader2.inject(environment), reader3.inject(environment))
        }
    }

What might work is adding a generic to your zip function for the Dependencies type. and then adding M.Dependencies == Dependencies to the where clause. I've not tried it myself. Hope that works!

extension MiddlewareReaderProtocol {
    public static func zip<each M: MiddlewareReaderProtocol, MOutput: MiddlewareProtocol, Dependencies>(
        _ readers: repeat each M,
        with map: @escaping @Sendable (repeat (each M).MiddlewareType) -> MOutput
    ) -> MiddlewareReader<Dependencies, MOutput>
    where M.Dependencies == Dependencies {
        MiddlewareReader { environment in
            map((repeat each readers).inject(environment))
        }
    }
}
1 Like

First, you need to "-enable-experimental-feature SameElementRequirements". Second, you should add a dummy generic parameter as an anchor for your constraints.

The signature will then be

protocol MiddlewareReaderProtocol {
    associatedtype MiddlewareType
    associatedtype Dependencies
}

protocol MiddlewareProtocol {}

struct MiddlewareReader<Dependencies, Output: MiddlewareProtocol> {}

func zip<
    each M: MiddlewareReaderProtocol, 
    MOutput: MiddlewareProtocol,
    Dependencies
>(
    readers: repeat each M,
    with: @escaping (repeat (each M).MiddlewareType) -> MOutput
) -> MiddlewareReader<Dependencies, MOutput> 
    where repeat (each M).Dependencies == Dependencies 
{
    fatalError()
}

It compiles with nightly toolchain.
PS: it is implemented by [Requirement Machine] Implement same-element requirements. by simanerush · Pull Request #70227 · swiftlang/swift · GitHub.

2 Likes

There’s also a hacky way

That's literally zip, though. The question in this thread isn't really about zip. It's actually about how to express this:

protocol Protocol<A> { associatedtype A }
func f<each P: Protocol<Int>>(_: repeat each P) { } // Same-element requirements are not yet supported

Be advised the implementation of this feature is incomplete. There are several code paths that still need updating to take same-element requirements into account, so less trivial examples won’t work.

3 Likes