问题
This question is about _ as used in type constructor and not when used in defining existential types.
So the question is what is the difference when _
is used as type parameter instead of a variable like T
. For example difference between F[_]
and F[T]
.
The only difference I can think of is that with F[_]
the parameter itself can have as many holes as possible...that is F[_]
can become F[Int]
or F[Future[Option[Int]]]
etc...while when you have F[T]
the T
can only be a proper type...that is F[String]
or F[Int]
etc.
Is this a correct assumption? and is that the main difference between F[_]
and F[T]
? or there are more?
What about the case where the two are used as type parameters? For example, what is the difference between trait Functor [F[_]]
and trait Functor [F[T]]
?
Is there any semantic difference if the functor trait is defined as trait Functor [F[_]]
instead of trait Functor [F[T]]
?
回答1:
To quote the specification:
The above scoping restrictions are generalized to the case of nested type parameter clauses, which declare higher-order type parameters. Higher-order type parameters (the type parameters of a type parameter
t
) are only visible in their immediately surrounding parameter clause (possibly including clauses at a deeper nesting level) and in the bounds of t. Therefore, their names must only be pairwise different from the names of other visible parameters. Since the names of higher-order type parameters are thus often irrelevant, they may be denoted with a_
, which is nowhere visible.Example
Here are some well-formed type parameter clauses:
[S, T] [@specialized T, U] [Ex <: Throwable] [A <: Comparable[B], B <: A] [A, B >: A, C >: A <: B] [M[X], N[X]] [M[_], N[_]] // equivalent to previous clause [M[X <: Bound[X]], Bound[_]] [M[+X] <: Iterable[X]]
So if you have no bounds, as in Functor [F[T]]
, there's no difference at all from Functor [F[_]]
.
回答2:
The only difference I can think of is that with
F[_]
the parameter itself can have as many holes as possible...that isF[_]
can becomeF[Int]
orF[Future[Option[Int]]]
etc...while when you haveF[T]
theT
can only be a proper type...that isF[String]
orF[Int]
etc.Is this a correct assumption?
Note that Future[Option[Int]]
is a proper type of the same kind as Int
or String
. We can convince ourself by using :kind
command in Scala REPL
scala> :kind -v Future[Option[Int]]
scala.concurrent.Future[Option[Int]]'s kind is A
*
This is a proper type.
scala> :kind -v Int
Int's kind is A
*
This is a proper type.
To drive the point, consider the following complicated-looking type
Function3[Int, Tuple2[Double, List[Int]], Char, Future[Either[String, Int]]]
It is still just a simple concrete *
type
scala> :kind -v Function3[Int, Tuple2[Double, List[Int]], Char, Future[Either[String, Int]]]
(Int, (Double, List[Int]), Char) => scala.concurrent.Future[Either[String,Int]]'s kind is A
*
This is a proper type.
Hence we see the shape of Future[Option[Int]]
is simply *
, and F[_]
does not need any extra "holes" to fit it. Both F[_]
and F[T]
type constructors take a type argument of exactly same shape, namely *
, no more, nor less. For example, let us try to fit in more than it can handle
trait Bar[F[_]] // Bar is type constructor of higher order kind - shape (* -> *) -> *
def g[F[_]] = println("g takes type constructor type argument of * -> * shape")
scala> g[Bar]
^
error: kinds of the type arguments (Bar) do not conform to the expected kinds of the type parameters (type F).
Bar's type parameters do not match type F's expected parameters:
type F has 1 type parameter, but type _ has 0
This errors because actual (* -> *) -> *
shape of Bar
does not fit expected * -> *
shape of F
.
来源:https://stackoverflow.com/questions/49762658/difference-between-f-and-ft-in-scala-when-used-in-type-constructors