<div dir="ltr">Have been trying and thinking a lot of different functional patterns lately and came up with a lack of something. Working name for it is "aliascase", though I hope we can come up with something better together. Here it is in essence:<br><div><br></div><div>Let's say we have a generic <b>typealias</b> Something and it's generic. Though I would like to extend it and make it's value be dependent on A. A passing isn't always enough (will bring example later).</div><div>
<p class="gmail-p1"><span class="gmail-s1"><b>typealias</b></span><span class="gmail-s2"> Something<A> = </span><span class="gmail-s3">Void</span></p><p class="gmail-p1"><span class="gmail-s3"><b>aliascase</b> Something = A? </span>where A == Int</p><p class="gmail-p1"><span class="gmail-s3"><b>aliascase</b> Something = [A.Element] </span>where A : Sequence<br></p><p class="gmail-p1">What it means is that at the end you have a default Type and special situations you want to handle differently. Considering it can work in junction with <b>associatedtype</b> constraints, <b>aliascase</b> can be constrainted as well to whatever fits into <b>associatedtype</b>.</p><p class="gmail-p1">Let's bring another more like a real life example:</p><p class="gmail-p1">protocol Monad {<br></p><p class="gmail-p1">associatedtype A</p><p class="gmail-p1">associatedtype R<MA, MB> : Monad where MA : Monad, MB : Monad, R.A == MB.A</p><p class="gmail-p1">func flatMap<MB : Monad>(_ f:(A)->MB) -> R<Self, MB></p><p class="gmail-p1">}</p><p class="gmail-p1"><br></p><p class="gmail-p1">Why do we need to do it in such a complicated way?? Answer: monad mixing.</p><p class="gmail-p1">Let's say we have two types Optional, Array and Future. All are monads.<br></p><p class="gmail-p1">Let's think what are the desired results of monad mixing with flatMap here:</p><p class="gmail-p1">1. Optional flatMap Optional => Optional</p><p class="gmail-p1">2. Optional flatMap Array => Array</p><p class="gmail-p1">3. Optional flatMap Future => Future<br></p><p class="gmail-p1"><br></p><p class="gmail-p1">4. Future flatMap Future => Future</p><p class="gmail-p1">5. Future flatMap Optional => Future<br></p><p class="gmail-p1">6. Future flatMap Array => Future<Array<A>></p><p class="gmail-p1"><br></p><p class="gmail-p1">7. Array flatMap Array => Array</p><p class="gmail-p1">8. Array flatMap Optional => Array<br></p><p class="gmail-p1">9. Array flatMap Future => Future<Array<A>></p><div><br></div><p class="gmail-p1">In most cases, we can just take the MB and make it the result of our expression (which is exactly what will be the default case for typealias). But it's not enough when talking about advanced monads.</p><p class="gmail-p1">In the case above typealiases would look like:</p><p class="gmail-p1">//In Optional.swift<br></p><p class="gmail-p1">extension Optional : Monad {</p><p class="gmail-p1">typealias A = Wrapped</p><p class="gmail-p1">typealias R<MA, MB> = MB //easy</p><p class="gmail-p1">}</p><p class="gmail-p1">//In Array.swift</p><p class="gmail-p1">extension Array : Monad {</p><p class="gmail-p1">typealias A = Element</p><p class="gmail-p1">typealias R<MA, MB> = Array<MB.A> //defaults to array</p><p class="gmail-p1">}</p><p class="gmail-p1">//In Future.swift</p><p class="gmail-p1">extension Future : Monad {</p><p class="gmail-p1">typealias A = Value</p><p class="gmail-p1">typealias R<MA, MB> = Future<MB.A></p><p class="gmail-p1"><span class="gmail-s3"><b>aliascase</b> R<MA, MB> = Future<MB> where MB : Sequence //we still fit the criteria, but enclose all multielement Monads</span><br></p><p class="gmail-p1">}</p><p class="gmail-p1">extension Array {</p><p class="gmail-p1"><b>aliascase </b>R<MA, MB> = Future<MB> where MB : FutureProtocol //we need different behaviour in this case<br></p><p class="gmail-p1">}</p><div><br></div></div><div>I know it's from quite some advanced use cases and it's not for everyday use. Though it's mandatory to get a really good middleware foundation (which IS for daily use).</div></div>