[Pitch] Type alias with aliascase


(Daniel Leping) #1

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:

Let's say we have a generic *typealias* 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).

*typealias* Something<A> = Void

*aliascase* Something = A? where A == Int

*aliascase* Something = [A.Element] where A : Sequence

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 *associatedtype* constraints, *aliascase* can be constrainted
as well to whatever fits into *associatedtype*.

Let's bring another more like a real life example:

protocol Monad {

associatedtype A

associatedtype R<MA, MB> : Monad where MA : Monad, MB : Monad, R.A == MB.A

func flatMap<MB : Monad>(_ f:(A)->MB) -> R<Self, MB>

}

Why do we need to do it in such a complicated way?? Answer: monad mixing.

Let's say we have two types Optional, Array and Future. All are monads.

Let's think what are the desired results of monad mixing with flatMap here:

1. Optional flatMap Optional => Optional

2. Optional flatMap Array => Array

3. Optional flatMap Future => Future

4. Future flatMap Future => Future

5. Future flatMap Optional => Future

6. Future flatMap Array => Future<Array<A>>

7. Array flatMap Array => Array

8. Array flatMap Optional => Array

9. Array flatMap Future => Future<Array<A>>

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.

In the case above typealiases would look like:

//In Optional.swift

extension Optional : Monad {

typealias A = Wrapped

typealias R<MA, MB> = MB //easy

}

//In Array.swift

extension Array : Monad {

typealias A = Element

typealias R<MA, MB> = Array<MB.A> //defaults to array

}

//In Future.swift

extension Future : Monad {

typealias A = Value

typealias R<MA, MB> = Future<MB.A>

*aliascase* R<MA, MB> = Future<MB> where MB : Sequence //we still fit the
criteria, but enclose all multielement Monads

}

extension Array {

*aliascase *R<MA, MB> = Future<MB> where MB : FutureProtocol //we need
different behaviour in this case

}

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).