Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multiple type parameter lists #4719

Closed
scabug opened this issue Jun 20, 2011 · 6 comments
Closed

multiple type parameter lists #4719

scabug opened this issue Jun 20, 2011 · 6 comments
Labels
enhancement fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/)

Comments

@scabug
Copy link

scabug commented Jun 20, 2011

(quoting Miles Sabin)

We can encode multiple type parameter blocks on
methods in current Scala, albeit inefficiently and clumsily,

 def foo[A1, A2][B1, B2](p1 : (A1, B1)) : (A2, B2) = ...

can be encoded as,

 def foo[A1, A2] = new { def apply[X1, X2, B1, B2](p1 : (A1,
B1))(implicit ev : X1 =:= A1) : (A2, B2) = ... }

(/quoting Miles Sabin)

Multiple type parameter lists would internally be represented by nested PolyTypes, which is possible due to the NullaryMethodType refactoring. I see two options for type inference:

  • reduce to single type parameter list by bunching all type parameters together
  • solve type parameters in batches, so that the concrete type chosen for later type parameters does not influence the inference of earlier type parameters (in lists on the left), au contraire, later type param's inference depends on the types chosen for type params in lists on their left (see also fundeps in haskell)

see also: named and default type parameters

@scabug
Copy link
Author

scabug commented Jun 20, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4719?orig=1
Reporter: @adriaanm

@scabug
Copy link
Author

scabug commented Jun 20, 2011

@milessabin said:
I was assuming option (2) would be the way to go, if only for consistency with the semantics of multiple value parameter lists.

@scabug
Copy link
Author

scabug commented Apr 19, 2014

@Atry said (edited on Apr 19, 2014 3:19:57 AM UTC):

type ResultOf[Function] = {
  type Result
}
object ResultOf {
  type ResultOfFunction1[A, R] = ResultOf[A => R] {
    type Result = R
  }
  implicit def resultOfFunction1[A, R]: ResultOfFunction1[A, R] = null
}
def betterImplicitly[RequiredType][ActuallyType](implicit i: RequiredType with ActuallyType) = i
val functionTypeTrait = betterImplicitly[ResultOf[String => Int]]
val shouldBeInt: functionTypeTrait.Result = 0

With multiple type parameter lists support, we will have a better implicitly method, which infers a specified type instead of the required type.

@nbenns
Copy link

nbenns commented May 2, 2017

It would be nice to have multiple parameter lists on type aliases as well:

Then I could turn this mess:

import scala.language.higherKinds

type Curry2[F[_, _]] = {
  type Apply[A] = {
    type Apply[B] = F[A, B]
  }
}

trait Functor[F[_]] {
  def map[A, B](op: A => B)(orig: F[A]): F[B]
}

type Reader = Curry2[Function]

implicit def ReaderFunctor[R] = new Functor[Reader#Apply[R]#Apply] {
  override def map[A, B](op: A => B)(orig: R => A): R => B =
    orig andThen op
}

def map[A,B,F[_]](op: A => B)(fa: F[A])(implicit functor: Functor[F]): F[B] =
  functor.map(op)(fa)

def toStringContainer[F[_]](a: F[Int])(implicit functor: Functor[F]) = map[Int, String, F](_.toString)(a)

val id: Int => Int = identity

val out: Int => String = toStringContainer[Reader#Apply[Int]#Apply](id)
out(2)

into:

import scala.language.higherKinds

type Curry2[F[_, _]][A][B] = F[A, B]

trait Functor[F[_]] {
  def map[A, B](op: A => B)(orig: F[A]): F[B]
}

type Reader = Curry2[Function]

implicit def ReaderFunctor[R] = new Functor[Reader[R]] {
  override def map[A, B](op: A => B)(orig: R => A): R => B =
    orig andThen op
}

def map[A,B][F[_]](op: A => B)(fa: F[A])(implicit functor: Functor[F]): F[B] =
  functor.map(op)(fa)

/*
  Not sure if it would be possible to get this clean,
  or if the implicit would cause this to fail.
  Might also have to pass toString like `(_:Int).toString`
*/
def toStringContainer = map(_.toString)

val id: Int => Int = identity

val out: Int => String = toStringContainer[Reader[Int]](id)
out(2)

An alternative would be to implement Apply for type parameters on the first example, at least it would clean up the use of the parameters instead of using the projection syntax.

A note that the kind projection plugin only fixes some of these issues, but not all.

@adriaanm adriaanm removed their assignment Sep 28, 2018
@atkinsonjoshua31
Copy link

Open

@SethTisue SethTisue added the fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) label Apr 1, 2023
@SethTisue
Copy link
Member

SethTisue commented Apr 1, 2023

this is now out of scope for Scala 2

for Scala 3,

the feature remains experimental for now, and thus only available in nightly builds:

% scala-cli -S 3.nightly
Welcome to Scala 3.3.1-RC1-bin-20230331-7262437-NIGHTLY-git-7262437
scala> import scala.language.experimental.clauseInterleaving
scala> def foo[A](x: A)[B](y: B) = (x, y)
def foo[A](x: A)[B](y: B): (A, B)

but it seems likely to eventually become fully part of the language

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Apr 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/)
Projects
None yet
Development

No branches or pull requests

5 participants