在 GitHub 上编辑此页面

多态函数类型

多态函数类型是接受类型参数的函数类型。例如

// A polymorphic method:
def foo[A](xs: List[A]): List[A] = xs.reverse

// A polymorphic function value:
val bar: [A] => List[A] => List[A]
//       ^^^^^^^^^^^^^^^^^^^^^^^^^
//       a polymorphic function type
       = [A] => (xs: List[A]) => foo[A](xs)

Scala 已经有了多态方法,即接受类型参数的方法。上面的方法 foo 就是一个示例,它接受类型参数 A。到目前为止,不可能将此类方法转换为多态函数值,如上面的 bar,它可以作为参数传递给其他函数,或作为结果返回。

在 Scala 3 中,现在可以做到这一点。上面 bar 值的类型是

[A] => List[A] => List[A]

此类型描述了将类型 A 作为参数,然后获取类型为 List[A] 的列表,并返回类型为 List[A] 的列表的函数值。

更多详情

示例用法

当方法的调用者需要提供一个多态函数时,多态函数类型特别有用,这意味着它应该接受任意类型作为其输入的一部分。

例如,考虑我们有一个数据类型以强类型方式表示简单语言的表达式(仅包含变量和函数应用程序)的情况

enum Expr[A]:
  case Var(name: String)
  case Apply[A, B](fun: Expr[B => A], arg: Expr[B]) extends Expr[A]

我们希望为用户提供一种方法,以便对给定 Expr 的所有直接子表达式进行函数映射。这要求给定的函数是多态的,因为每个子表达式可能具有不同的类型。以下是使用多态函数类型实现此功能的方法

def mapSubexpressions[A](e: Expr[A])(f: [B] => Expr[B] => Expr[B]): Expr[A] =
  e match
    case Apply(fun, arg) => Apply(f(fun), f(arg))
    case Var(n) => Var(n)

以下是使用此函数将给定表达式中的每个子表达式用调用某个 wrap 函数(定义为变量)进行包装的方法

val e0 = Apply(Var("f"), Var("a"))
val e1 = mapSubexpressions(e0)(
  [B] => (se: Expr[B]) => Apply(Var[B => B]("wrap"), se))
println(e1) // Apply(Apply(Var(wrap),Var(f)),Apply(Var(wrap),Var(a)))

与类型 Lambda 的关系

多态函数类型不要与类型 Lambda混淆。前者描述多态类型,而后者是类型级别上的实际函数值。

理解差异的一个好方法是注意到类型 Lambda 应用于类型,而多态函数应用于项:可以通过在方法体传递类型参数 bar[Int] 来调用上面的函数 bar。另一方面,给定类型 Lambda(例如 type F = [A] =>> List[A]),可以在类型表达式调用 F,如 type Bar = F[Int]