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

Streamline Function and Tuple #246

Closed Adam-Vandervorst closed 1 year ago

Adam-Vandervorst commented 3 years ago

Motivating example

  def rightArgs(law: LT[R, V], r: R, it: Iterable[V]): Boolean = law match
    case s: ((R) => Boolean) => s(r)
    case s: ((R, V) => Boolean) => it.forall(x => s(r, x))
    case s: ((R, V, V) => Boolean) => it.forall(x => it.forall(y => s(r, x, y)))
    case s: ((R, V, V, V) => Boolean) => it.forall(x => it.forall(y => it.forall(z => s(r, x, y, z))))

and many others (in the standard library and compiler, too) could be made parametric with a few extra utilities.

Domain and codomain types

Currently, it is hard to process functions because you can only match them direct-style. Adding the following would make that easier:

trait Function0[+R] ...
  type Domain = EmptyTuple
  type CoDomain = R

trait Function1[-T1, +R] ...
  type Domain = Tuple1[T1]
  type CoDomain = R

trait Function2[-T1, -T2, +R] ...
  type Domain = Tuple2[T1, T2]
  type CoDomain = R

With this feature, you easily use the power of the function Tuple.Map and Tuple.Concat.

Re-assembling or Type-splat

In some cases, you want to take the extracted and processed domains and codomains, and produce a new function type without hard-coding everything. This can be solved either with a match type taking [Domain, CoDomain] and producing Function[*Domain, CoDomain] or with a type-level splat like the one alluded to with *Domain (expanding a tuple into the required arguments).

Base trait for FunctionN

I was surprised to learn there is no common trait for FunctionN as there is for TupleN (namely Tuple). Instead, Function is an alias for Function1, which is inconsistent and not very useful. I propose (for matching and type-safety purposes) that they do get a common trait.

Tupled functions

Right now, the smallest function that has this method is Function2 (https://dotty.epfl.ch/api/scala/Function2.html). I see no reason why this can not be done for Function1 and Function0, removing the special cases I have now (as in https://github.com/lampepfl/dotty/issues/13800).

Result

If everything works out here, a lot of boilerplate around functions could be removed.