类型构造函数参数推断

Type constructor parameter inference

我正在学习“Scala with cats”。在 3.5.2(第 58 页,底部)中有一个示例:

def doMath[F[_]](start: F[Int])(implicit functor: Functor[F]): F[Int] =
    start.map(n => n + 1 * 2)

而且用法非常简单:

import cats.instances.option._ // for Functor
import cats.instances.list._
// for Functor
doMath(Option(20))
// res3: Option[Int] = Some(22)
doMath(List(1, 2, 3))
// res4: List[Int] = List(3, 4, 5)

如何理解方法签名中的类型构造函数(F[_])?前面几页曾说过,应该提供类型参数来创建类型。这里整个东西 (F[_]) 是一个类型参数,看起来 _ 是一个通配符,因此编译器可以推断出 F.

的类型参数

类型构造函数 F[_] 必须是 Functor 类型类的成员。此约束由隐式参数列表

放在 F
(implicit functor: Functor[F])

整个签名

def doMath[F[_]](start: F[Int])(implicit functor: Functor[F]): F[Int]

可能解读如下

Given any type constructor F that is a member of Functor typeclass, then doMath can transform effectful value of type F[Int] to another effectful value of type F[Int].

我在这里使用短语有效值来强调它不是原始类型的值,例如Int,而是应用类型后构造的类型值构造函数 F 键入参数 Int,即 F[Int].

此外,我在 sense of

中使用短语 的成员

forms a, or participates in, or has a relationship

请注意,在此上下文中使用下划线 _ 与推理无关。 F[X]F[_] 类型构造函数符号的意思正是 的意思。方法签名的其余部分没有使用类型参数 X,因此按照惯例我们使用下划线语法 F[_]。另一个约定是在F[x]中使用小写的x,而不是F[X],以强调x不被使用。

确实 F[_] 本身就是一个类型参数,当类型构造函数 Functor 应用于它时,我们得到 proper 类型 Functor[F] 尽管 FFunctor 都是类型构造函数,例如

scala> :kind -v List
List's kind is F[+A]
* -(+)-> *
This is a type constructor: a 1st-order-kinded type.

scala> :kind -v cats.Functor
cats.Functor's kind is X[F[A]]
(* -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.

scala> :kind -v cats.Functor[List]
cats.Functor[List]'s kind is A
*
This is a proper type.