让我通过一些消歧来弥补开始的一些混乱。我喜欢用价值水平的类比来解释这一点,因为人们往往更熟悉它。
类型构造函数是一种可以应用于类型参数以“构造”类型的类型。
值构造函数是可以应用于值参数以“构造”值的值。
值构造函数通常称为“函数”或“方法”。这些“构造函数”也被称为“多态”(因为它们可用于构造不同“形状”的“东西”)或“抽象”(因为它们抽象出不同多态实例之间的差异)。
在抽象/多态的上下文中,一阶是指抽象的“一次性使用”:您对一个类型进行一次抽象,但该类型本身不能对任何东西进行抽象。 Java 5 泛型是一阶的。
上述抽象特征的一阶解释是:
类型构造函数是一种类型,您可以将其应用于正确的类型参数以“构造”正确的类型。
值构造函数是一个值,您可以将其应用于正确的值参数以“构造”正确的值。
为了强调不涉及抽象(我猜你可以称之为“零阶”,但我没有看到它在任何地方使用过),例如值1或类型String,我们通常会说一些是一个“正确的”值或类型。
正确的值是“立即可用的”,因为它不等待参数(它不抽象它们)。将它们视为您可以轻松打印/检查的值(序列化函数是作弊!)。
正确的类型是对值进行分类的类型(包括值构造函数),类型构造函数不会对任何值进行分类(它们首先需要应用于正确的类型参数以产生正确的类型)。要实例化一个类型,有必要(但不充分)它是一个正确的类型。 (它可能是一个抽象类,或者您无权访问的类。)
“高阶”只是一个通用术语,表示重复使用多态性/抽象。对于多态类型和值来说,这意味着同样的事情。具体来说,高阶抽象抽象了一些抽象的东西。对于类型,术语“higher-kinded”是更一般的“higher-order”的特殊用途版本。
因此,我们表征的高阶版本变为:
类型构造函数是一种可以应用于类型参数(正确类型或类型构造函数)以“构造”正确类型(构造函数)的类型。
值构造函数是可以应用于值参数(正确值或值构造函数)以“构造”正确值(构造函数)的值。
因此,“高阶”仅仅意味着当您说“对 X 进行抽象”时,您是认真的!被抽象出来的X 并没有失去它自己的“抽象权”:它可以抽象它想要的一切。 (顺便说一下,我在这里使用动词“抽象”来表示:省略对值或类型的定义不重要的东西,以便抽象的用户可以改变/提供它作为参数.)
以下是一些正确、一阶和高阶值和类型的示例(灵感来自 Lutz 通过电子邮件提出的问题):
proper first-order higher-order
values 10 (x: Int) => x (f: (Int => Int)) => f(10)
types (classes) String List Functor
types String ({type λ[x] = x})#λ ({type λ[F[x]] = F[String]})#λ
使用的类被定义为:
class String
class List[T]
class Functor[F[_]]
为了避免通过定义类的间接性,您需要以某种方式表达匿名类型函数,这些函数在 Scala 中无法直接表达,但是您可以使用结构类型而没有太多的语法开销(#λ 样式是由于 @ 987654321@afaik):
在一些支持匿名类型函数的假设未来版本的 Scala 中,您可以将示例中的最后一行缩短为:
types (informally) String [x] => x [F[x]] => F[String]) // I repeat, this is not valid Scala, and might never be
(就个人而言,我很遗憾曾经谈论过“高级类型”,它们毕竟只是类型!当您绝对需要消除歧义时,我建议说诸如“类型构造函数参数”,“类型构造函数成员”或“类型构造函数别名”,以强调您不是在谈论正确的类型。)
ps:更复杂的是,“多态”在另一种意义上是模棱两可的,因为多态类型有时意味着一个普遍量化的类型,例如Forall T, T => T,这是一个正确的类型,因为它对多态值进行分类(在Scala,这个值可以写成结构类型{def apply[T](x: T): T = x})