简体   繁体   English

F[_] 和 F[T] 在 Scala 中用于类型构造函数时的区别

[英]Difference between F[_] and F[T] In Scala when used in type constructors

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 .所以问题是当_用作类型参数而不是像T这样的变量时有什么区别。 For example difference between F[_] and F[T] .例如F[_]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.我能想到的唯一区别是,使用F[_]参数本身可以有尽可能多的孔……也就是说F[_]可以变成F[Int]F[Future[Option[Int]]]等等......而当你有F[T]T只能是一个正确的类型......即F[String]F[Int]等。

Is this a correct assumption?这是一个正确的假设吗? and is that the main difference between F[_] and F[T] ?这是F[_]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]] ?例如, trait Functor [F[_]]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]] ?如果 functor trait 被定义为trait Functor [F[_]]而不是trait Functor [F[T]]有什么语义上的区别吗?

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.高阶类型参数(类型参数t的类型参数)仅在其紧邻的参数子句(可能包括更深嵌套级别的子句)和 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[_]] .因此,如果您没有边界,就像在Functor [F[T]] ,那么与Functor [F[_]]没有任何区别。

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.我能想到的唯一区别是,使用F[_]参数本身可以有尽可能多的孔……也就是说F[_]可以变成F[Int]F[Future[Option[Int]]]等等......而当你有F[T]T只能是一个正确的类型......即F[String]F[Int]等。

Is this a correct assumption?这是一个正确的假设吗?

Note that Future[Option[Int]] is a proper type of the same kind as Int or String .请注意, Future[Option[Int]]是与IntString类型相同的正确类型。 We can convince ourself by using :kind command in Scala REPL我们可以通过在 Scala REPL 中使用:kind命令来说服自己

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.因此,我们看到Future[Option[Int]]的形状只是* ,而F[_]不需要任何额外的“孔”来适应它。 Both F[_] and F[T] type constructors take a type argument of exactly same shape, namely * , no more, nor less. F[_]F[T]类型构造函数都采用完全相同形状的类型参数,即* ,不多也不少。 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 .此错误是因为实际(* -> *) -> * Bar形状不符合预期* -> * F形状。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM