title: How to implement a zip function for the SwiftTask framework?
body: <p>I'm trying to implement a generic <code>Task.zip</code> class function for the <a href="https://github.com/ReactKit/SwiftTask" rel="nofollow">SwiftTask</a> framework. The function takes a tuple of tasks and returns a task of tuples much like the standard library function <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Functions/index.html#//apple_ref/swift/func/s:FSs3zipu0_Rq_Ss12SequenceTypeq0_S__FTq_q0__GVSs12Zip2Sequenceq_q0__" rel="nofollow">zip</a> and is a type of <a href="http://en.wikipedia.org/wiki/Convolution_(computer_science)" rel="nofollow">convolution</a>. </p>
  
  <p>My first attempt used the following signature:</p>
  
  <p><code>class func zip&lt;P1, V1, R1, P2, V2, R2&gt;(task1: Task&lt;P1, V1, R1&gt;, _ task2: Task&lt;P2, V2, R2&gt;) -&gt; Task&lt;(P1, P2), (V1, V2), (R1?, R2?)&gt;</code></p>
  
  <p>Although the function compiles, calling it triggers the follow types of compiler error:</p>
  
  <p><code>'Cannot invoke 'zip' with an argument list of type '(Task&lt;String, String, NSError&gt;, Task&lt;NSRange, Float, NSError&gt;)'</code></p>
  
  <p>Following is a sketch of the implementation (untested). Getting the call site to compile is a first step.</p>
  
  <pre><code>public class func zip&lt;P1, V1, R1, P2, V2, R2&gt;(task1: Task&lt;P1, V1, R1&gt;, _ task2: Task&lt;P2, V2, R2&gt;) -&gt; Task&lt;(P1, P2), (V1, V2), (R1?, R2?)&gt;
  {
      return Task&lt;(P1, P2), (V1, V2), (R1?, R2?)&gt; { progress, fulfill, reject, configure in
  
          var completedCount = 0
          var rejectedCount = 0
          let totalCount = 2
  
          let cancelAll : Void -&gt; Void = {
              task1.cancel()
              task2.cancel() 
          }
  
          let pauseAll : Void -&gt; Void = {
              task1.pause()
              task2.pause() 
          }
  
          let resumeAll : Void -&gt; Void = {
              task1.resume()
              task2.resume() 
          }
  
          task1.success { (value: V1) -&gt; Void in
  
              synchronized(self) 
              {
                 completedCount++
  
                  if completedCount == totalCount 
                  {
                      fulfill( (task1.value!, task2.value!) )
                  }
              }
          }.failure { (error, isCancelled) -&gt; Void in
  
              synchronized(self) 
              {
                  reject( error, nil )
                  cancelAll() 
              }
          }
  
          task2.success { (value: V2) -&gt; Void in
  
              synchronized(self) 
              {
                  completedCount++
  
                  if completedCount == totalCount 
                  {
                      fulfill( (task1.value!, task2.value!) )
                  }
              }
          }.failure { (error, isCancelled) -&gt; Void in
  
              synchronized(self) 
              {
                  reject( nil, error )
                  cancelAll() 
              }
          }
  
      configure.pause = { pauseAll() }
      configure.resume = { resumeAll() }
      configure.cancel = { cancelAll() }
  
      }.name("Task.zip")
  }
  </code></pre>
  
  <p>And call site:</p>
  
  <pre><code>let task1 = listener as Task&lt;String, String, NSError&gt; 
  let task2 = praise as Task&lt;NSRange, Float, NSError&gt; 
  let zipped = Task.zip(task1, task2)
  
  // Error: Cannot invoke 'zip' with an argument list of type '(Task&lt;String, String, NSError&gt;, Task&lt;NSRange, Float, NSError&gt;)'
  </code></pre>
  
  <p>I understand that a <code>Task.zip</code> maybe wrong-headed, or that the implementation is incorrect. Please let me know your thoughts - all help much appreciated!</p>