<div dir="ltr">(more inline)<br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 30, 2016 at 6:30 AM, plx via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div>A few more comments inlined now that I’ve read it.</div><div><span class=""><div><br></div></span><div>I like the `fold` construct but feel like for this use it needs a few more options-or-variants.</div><div><br></div><div>The first one is some more-explicit support for “early exit”.</div><div><br></div><div>EG for the cascading-lookup example, you can convert it to this `#fold`:</div><div><br></div><div><div>  private func lookupKey(key: K) -&gt; V? {</div><div>    return #fold(</div><div>      start: nil,</div><div>      reducer: { </div><div>        (table, value)</div><div>        in</div><div>        return value ?? table[key]</div><div>      },</div><div>      values: tables</div><div>    )</div><div>  }</div><div><br></div><div>…but unless the compiler is very savvy you are going to have a bunch of unneeded stuff even after your “success” (it won’t do another lookup, but it just seems wasteful and could be wasteful in other contexts).</div><div><br></div><div>Relatedly, that `#fold` is only going to work if the compiler can infer a proper type for the `table` argument to the `reducer`.</div><div><br></div><div>If you have to specify the types explicitly via a helper function, it seems like this won’t work:</div><div><br></div><div><div>  func lookupIfNecessary&lt;T:LookupTable where T.Key == K, T.Value == V&gt;(table: T,  key: K, value: V?) -&gt; V? {</div><div>     return value ?? table[key]</div><div>  }</div></div><div><br></div><div>…b/c the signature isn’t right for the reducer, and it seems like this might work:</div><div><br></div><div><div>  func createLookupFunction&lt;T:LookupTable where T.Key == K, T.Value == V&gt;(key: K) -&gt; (T, V?) -&gt; V? {</div><div>     return { (t,v) in return v ?? t[key] }</div><div>  }</div></div></div></div></div></blockquote><div><br></div><div>Yes, the fundamental problem here is that a user might need to pass an arbitrary number of additional, non-pack-dependent arguments into the reducer.</div><div><br></div><div>One possible solution might be an &quot;AdditionalInfo&quot; parameter representing some constant always passed into the reducer function. This would effectively do the same thing as a closure closing over some common state, but maybe be a little less horrific to the user?</div><div><br></div><div>#fold(start: U, constantData: V, reducer: (#requirements, U, V) -&gt; U, values: T...)</div><div><br></div><div>(I ran into this issue some time ago as an app developer where I needed to connect two APIs. One of them took fewer arguments than the other, and we needed to preserve the additional context. The offending API was also vended by a 3rd-party library, so it couldn&#39;t be changed. I remember an elegant solution using multiple argument list currying, a feature which is now gone from Swift...)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><br></div><div><div><div>  private func lookupKey(key: K) -&gt; V? {</div><div>    return #fold(</div><div>      start: nil,</div><div>      reducer: createLookupFunction(key), // &lt;- should work…I hope...</div><div>      values: tables</div><div>    )</div><div>  }</div></div><div><br></div><div>…but it seems a bit convoluted; perhaps there’s a trick here? Or perhaps a variant with an adjusted signature like so:</div><div><br></div><div>  // perhaps inout K ? or as an option?</div><div>  #foldWithContext(context: K, start: U, reducer:(#requirements,U,K) -&gt; U, values: (T…)) -&gt; U</div><div><br></div><div>Relatedly, having `#fold` variants like the above that include the current index could address a lot of the uses for integer-based indexing:</div><div><br></div><div>  #indexedFold(start: U, reducer:(#requirements,U,Int) -&gt; U, values: (T…)) -&gt; U</div><div><br></div><div>…(the above can be done w/out dedicated support, but dedicated support might be more compiler-friendly on this one).</div></div></div></div></div></blockquote><div><br></div><div>Here&#39;s a revised signature for #fold(), taking in account the things you requested (which are good points, the Objective-C &quot;BOOL*&quot; arguments on enumeration blocks and the .enumerate() method on Swift collections attest to that):</div><div><br></div><div>#fold&lt;...T, U&gt;(start: U, reducer: (#requirements, Int, U) -&gt; (U, Bool), values: T...) -&gt; U<br></div><div><br></div><div>The reducer takes in an Int which is provided as the index into the pack. It returns a tuple, (U, Bool), which can be used to specify early exist. There could be &quot;sugared&quot; versions of #fold which don&#39;t provide the index and/or the early return functionality; those wouldn&#39;t be too difficult to design.</div><div><br></div><div>(I didn&#39;t include the additionalInfo feature mentioned above, but it wouldn&#39;t be too hard to munge it in.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><div><br></div><div>Finally, after reading it over again I really find the `…` confusing beyond the initial declaration sites (as you can perhaps tell since I’ve been mis-using it in my replies).</div><div><br></div><div>I can’t come up with an alternative that isn’t a major regression for simple declarations, but if a more-explicit syntax could be invented I’d highly prefer it.</div></div></div></div></div></blockquote><div><br></div><div>The syntax is desperately in need of improvement. Even I had to read over my examples a few times to make sure I was using everything correctly.</div><div><br></div><div>I&#39;m thinking about a more tuple-oriented approach that would eliminate the distinction between packs and tuples everywhere except when calling or defining a generic function or defining a generic type, which might eliminate some of the confusion.</div></div><br></div></div>