让我通过消除歧义来弥补开始时的一些困惑。我喜欢用价值层面的类比来解释这一点,因为人们往往更熟悉它。
类型构造函数是一种类型,可以应用于类型参数以“构造”类型。
值构造函数是一个可以应用于值参数以“构造”值的值。
值构造函数通常称为“函数”或“方法”。这些“构造函数”也被认为是“多态的”(因为它们可以用来构造不同“形状”的“东西”),或者是“抽象的”(因为它们抽象了不同多态实例化之间的变化)。
在抽象/多态性上下文中,一阶指的是抽象的“单次使用”:对一个类型进行一次抽象,但该类型本身不能对任何东西进行抽象。Java 5泛型是一阶的。
上述抽象特征的一阶解释是:
类型构造函数是一种可以应用于适当类型参数以“构造”适当类型的类型。
值构造函数是一个值,您可以将其应用到适当的值参数以“构造”适当的值。
为了强调没有涉及抽象(我猜你可以称之为“零阶”,但我在任何地方都没有见过这种用法),例如值1或类型String,我们通常说某个值或类型是“适当的”值或类型。
适当的值是“立即可用”的,因为它不等待参数(它不抽象参数)。可以把它们看作是可以轻松打印/检查的值(序列化函数是欺骗!)
正确的类型是对值(包括值构造函数)进行分类的类型,类型构造函数不对任何值进行分类(它们首先需要应用于正确的类型参数以产生正确的类型)。要实例化一个类型,它必须是一个合适的类型(但还不够)。(它可能是一个抽象类,也可能是一个您无法访问的类。)
“高阶”只是一个通用术语,意思是重复使用多态性/抽象。对于多态类型和值也是如此。具体地说,高阶抽象是对某物的抽象,再对某物的抽象。对于类型,术语“高类”是更一般的“高阶”的特殊用途版本。
因此,我们的描述的高阶版本变成:
类型构造函数是一种可以应用于类型参数(适当类型或类型构造函数)以“构造”适当类型(构造函数)的类型。
值构造函数是一个可以应用于值参数(正确值或值构造函数)以“构造”正确值(构造函数)的值。
因此,“高阶”仅仅意味着当您说“对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中是无法直接表达的,但你可以使用结构类型,没有太多的语法开销(#λ style是由于https://stackoverflow.com/users/160378/retronym 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})