Rex Kerr | 14 Aug 2012 01:19
Picon
Gravatar

Re: Towards Scala 3

On Mon, Aug 13, 2012 at 6:50 PM, Alexander Kuklev <akuklev <at> gmail.com> wrote:
Mon, 2012-08-13 <at> 22:57:06 UTC+2, Rex Kerr:
Also, it would be nice to be able to have functions that can take generic type parameters:

  def f[T](t: T) = t
  f _     // Tell me, do you honestly want Nothing => Nothing here?!

I missed this. In the proposal above, functions can have generic type parameters.
The function you wrote would have the type {type T; val t: T} => T. (I omit annotations for brevity.)

I was just explaining what happened now, and why one might want something better.
 

But the more parsimonious solution to that is to have an appropriate type-level encoding (e.g. Generic[T]):

  val g: Function1[Generic[T],Generic[T]] = f _
  // g is instantiated to have def apply[T](t: T): T

I have considered type level encodings instead of annotations <at> Param and <at> Arg. Something like representing trait F[T] = {...} as trait F extends Generic1 = {private type T = super._1}, and trait ArgListOfF extends Tuple2 {val x: Int = super._1, val y: Int = super._2} for argument list of f(x: Int, y: Int). Unfortunately, there are two issues:
a) we need renaming rather than copying, something like trait F extends Generic1 = {type super._1 as T} and {val super._1 as x: Int},
b) it doesn't work really well with inheritance. Often we inherit from two different generic types trait F[A, B] extends X[A] with Y[B], if both X[_] and Y[_] now inherit from Generic1, how could we prevent the name conflict?

I don't think you quite understood my proposal.  My question is: what is the type of t in f[T](t: T) before the generic is made specific?  Your answer is: a type in a custom trait.  My answer is: sure, but you don't need a separate trait each time; you just need one marker/wrapper trait--let's call it G.  Then
  G[T] => R
is shorthand for
  Function1[G[T],R] {
    def apply[T](t: T) => R
  }
where G[T] pushes genericity from the class level to the method level (which with erasure can be both rigorously and trivially done).
 
 
I don't think we want named parameters on functions; type-matching seems like a much more useful generalization than argument-name matching.
Could you elaborate on this? What type matching and argument-name matching do you mean?

I mean that duplicate: (Int, String) => String is plenty of information for an interface.  You shouldn't need to know that Int was called n and String was called original--it clutters up the interface with dummy symbols.  What is the class corresponding to the supertype of the functions corresponding to these two methods?

  def f1(s: String): Int
  def f2(name: String): Int

By encoding these names into the trait it seems like you are presuming that I couldn't want to abstract across these two functions.

But I do.  Almost surely I do.

You've got the annotation backwards, I think:

trait ThreeArgs[T] extends (T,Int,Int) with FnArg {
  <at> named("t") val _1: T
  <at> named("a") val _2: Int
  <at> named("b") val _3: Int = 0
}

This is pretty much just tuple/function-arg unification.

  --Rex


Gmane