多型函數類型
多型函數類型是接受類型參數的函數類型。例如
// 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
的方法是在方法主體中傳遞類型引數 bar[Int]
給它。另一方面,給定類型 lambda(例如 type F = [A] =>> List[A]
),呼叫 F
的方法是在類型表達式中,例如 type Bar = F[Int]
。
在本文中