Higher Kinded Type 参数中下划线的使用规则

Rules for underscore usage in Higher Kinded Type parameters

我想知道为什么下面的工作(注意 Functor 或 Applicative 与示例无关)

trait Functor[F[_]]
trait Applicative[F[_]] extends Functor[F]

但不是

trait Functor[F[_]]
trait Applicative[F[_]] extends Functor[F[_]]

我的问题是 F 与 F[_]

这里的规则是什么?

特别是编译器给出了一个严重的错误:

F[_] takes no type parameters, expected: one

trait Functor[F[_]]表示Functor需要一个类型构造函数(一个有空洞的类型,当空洞被填充时产生新的类型).

那么,这里 trait Applicative[F[_]] extends Functor[F] 你是说 Applicative 也需要有一个孔的东西。因此,F 已经被理解为有一个洞的东西,因此将它传递给 Functor 是有意义的。

最后,这里的 extends Functor[F[_]]extends Functor[F[T] forSome { type T } ] 相同,所以你正在填补 F 中的空缺,因此它不再适用于 Functor.

下划线 (_) 在定义站点 (1) 和调用站点 (2) 具有不同的含义。

(1) 在定义站点下划线表示泛型(类型参数)是类型构造函数(* => *)而不是正确的类型(*)。

trait A[X]                        // X is a proper type, *
//     ^^^ definition
trait B[X]   extends  A[X]        // X is a proper type, *
//     ^^^ definition, ^^^ call

trait A[F[_]]                     // F is a type constructor, * => *
//      ^^^^ definition
trait B[F[_]]   extends  A[F]     // F is a type constructor, * => *
//      ^^^^ definition,  ^^^ call

因为在定义站点上已经强调过 F 是一个类型构造函数,所以在调用站点它总是被称为 F(不需要额外的 _如果您指的是相同类型的构造函数 F).

(2) 在调用点,对于类型构造函数(* => *) FF[_] 表示存在类型。存在类型是适当的类型 (*)。

trait A[X]                        // X is a proper type, *
//     ^^^ definition

trait B[F[_]]                     // F is a type constructor, * => *
                extends  A[F[_]]  // F[_] is an existential type, *
//      ^^^^ definition,   ^^^^ call

定义站点和调用站点都存在一个plan in Scala 3.2 (Dotty) to make F[_] mean the same

In Scala 3.2, the meaning of _ changes from wildcard to placeholder for type parameter.

因此以下将成为有效语法

trait Applicative[F[_]] extends Functor[F[_]] // Both F[_] represent type lambda [X] =>> F[X]

目的是将通配符(存在)类型 F[_] 替换为 F[?]。这在 Dotty REPL

中已经可见
Starting dotty REPL...
scala> val l: List[_] = List(42)
val l: List[?] = List(42)

如果使用 source:3.1 -deprecation 编译,警告已经出现

dotc -source:3.1 -deprecation Main.scala
-- Deprecation Warning: Main.scala:2:14 ----------------------------------------
2 |  val l: List[_] = List(42)
  |              ^
  |        `_` is deprecated for wildcard arguments of types: use `?` instead
1 warning found

为此,kind-projector 已 preemptively 将其类型 lambda 语法从 F[?] 更改为 F[*],以便为 Scala 3 existential 释放 ?类型。

作为旁注,请考虑当前如何在 Dotty

中表达类型构造函数的 kind
Starting dotty REPL...
scala> trait Functor[F <: [X] =>> Any]
     | trait Applicative[F <: [X] =>> Any] extends Functor[F]
// defined trait Functor
// defined trait Applicative

scala> trait Applicative[F <: [X] =>> Any] extends Functor[[X] =>> F[X]]
// defined trait Applicative

类型 [X] =>> Any 的语法类似于上面 Dmytro 提到的非正式符号 * => *