多态函数类型
多态函数类型是接受类型参数的函数类型。例如
// 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]
。
在本文中