lampepfl / dotty-feature-requests

Historical feature requests. Please create new feature requests at https://github.com/lampepfl/dotty/discussions/new?category=feature-requests
31 stars 2 forks source link

Nicer syntax for inductive coproducts #72

Open julienrf opened 5 years ago

julienrf commented 5 years ago

Currently, tuples can be manipulated as an inductive data structure (Unit being the terminal type, and *: the cons type). This is extremely useful for generic programming. It is worth noting that the Scala 2 user-facing syntax for tuples is still available:

(Int, String) =:= Int *: String *: Unit

Thus, end-users can use the familiar tuple syntax, but library authors can implement powerful data-type generic computations in terms of the inductive representation of tuples.

However, it is well known that we live in a world of dualities.

So, how does the developer experience look like for manipulating coproducts? Inductive coproducts can be represented with Nothing for the terminal type and Either for the cons type:

Either[A, Either[B, Nothing]]

Library authors can implement powerful data-type generic computations in terms of this inductive representation of coproducts.

However, end-users don’t have a nice syntax to work with. They have to carry these nested Either types. What about introducing the following syntax?

A ^ B =:= Either[A, Either[B, Nothing]]

We also need a corresponding term-level syntax for constructing and extracting A ^ B values:

val coproduct: Int ^ String = left(42)
coproduct match {
  case left(int) => ...
  case right(string) => ...
}

There is probably room for improvement here: unlike with tuples, the term-level syntax is not symmetric with the type-level syntax.

letalvoj commented 4 years ago

IMO in your example:

Currently, you can express something very close to what you are asking for

scala> type ^[L,R] = L Either R                                                                                          
// defined alias type ^[L, R] = Either[L, R]

scala> val nested: Int ^ String ^ Double ^ Boolean ^ Exception = Left(Left(Left(Right("yay!"))))                          
val nested: 
  Either[Either[Either[Either[Int, String], Double], Boolean], Exception] = Left(Left(Left(Right(yay!))))