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

前端 未结 2 901
轮回少年
轮回少年 2021-02-07 11:37

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 us

2条回答
  •  孤街浪徒
    2021-02-07 12:15

    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?

    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.

提交回复
热议问题