Scala 中的高级类型

Higher Kinded Types in Scala

我正在阅读《Scala 函数式编程》一书,在 Monoids 一章中,他们讨论了一个如下所示的 Monoid 接口:

trait Monoid[A] {
 def op(a1: A, a2: A): A
 def zero: A
}

后来,他们通过扩展这个接口来定义特定的Monoid实例。例如,

val intMonoid = new Monoid[Int] {
  ...
}

val listMonoid = new Monoid[List[Int]] {
  ...
}

我读完第 10 章后又读了几页,我发现 'higher kinded types' 根据书中的说法,它是任何类型,它本身是一种可以采用其他类型的类型。

trait Foldable[F[_]] {
 ...
 ...
}

所以根据这本书,可折叠性状是一种更高级的类型。我的问题是,Monoid[A] 对我来说也符合 'higher kinded type' 定义,因为它可以采用 List[A]。我的理解正确吗?如果不是,是什么让更高种类的类型成为 Scala 中的更高种类类型?

编辑:所以一元类型构造函数接受一个参数并生成一个类型。那么这里的这个案例呢?

def listMonoid[A] = new Monoid[List[A]] {
  ...
  ...
}

那么我的 listMonoid 函数是 HKT 吗?

一些术语:

  • 正确的类型(例如 Int)
  • 一阶类型(例如List[_]);我们也可以说一阶种类
  • 更高种类的类型(例如 Monad[M[_])

当你说

trait Monoid[A] {
  def op(a1: A, a2: A): A
  def zero: A
}

val listMonoid = new Monoid[List[Int]] {
  def op(l: List[Int], l2: List[Int]) =  List(1,2)
  def zero = List(1,2)
}

你正在用某种类型 A 参数化 Monoid 特征,它可以(正如你注意到的那样)是一个简单类型,也称为正确类型(例如 Int)或参数化类型(例如 List[Int],甚至 List[Set[Map[Int, Int]])。这使得 Monoid 成为一阶类型。我们也可以说它是一个一元类型构造函数——它需要一个类型来产生最终类型。

与 Monoid 不同,某些抽象(例如 Monad)需要由类型构造函数参数化。 Int 不再起作用了。它需要是 "some type than can produce another type"。由类型构造函数参数化的抽象(即由 "first-order type" 参数化)是 higher-kinded 类型。这是一个例子:

trait Monad[M[_]] {
  def op[A, B](m: M[A], f: A => M[B]): M[B]
  def zero[A](a: A): M[A]
}

object ListMonad extends Monad[List] {
  def op[A, B](m: List[A], f: A => List[B]) = m.flatMap(f)
  def zero[A](a: A) = List[A](a)
}

val listMonad = ListMonad.zero(42)
val result = ListMonad.op(listMonad, (i: Int) => List(i - 1, i, i + 1))

// result = List(41, 42, 43)

所以Monad一阶类型(一元类型构造函数)参数化,这使得Monad本身是高等类型.

请注意 Monad 如何不真正关心 class 级别上的 "inner type" 本身,因为它将由方法 op 和 [=21] 定义=].您也可以在 class ListMonad 的定义点说 trait Monad[M[A]] 和 "fix" 类型 A(例如,将其固定为 Int),但是您正在失去灵活性(您的然后 ListMonad 将只能构造和 flatMap a List[Int] 而你需要一个不同的 class 来表示 List[String]).

这与 Monoid 不同,Monoid 不是更高级的类型;它不需要类型构造函数来生成类型。如果它需要它,那么你永远不会有一个,比如说,Monoid[Int],因为 Int 不是类型构造函数。

还要注意我是怎么说 Monad 需要一个 unary 类型构造函数的,这意味着它只需要一种类型(不像 Map 需要两种类型)。类型构造函数通常用星号和箭头表示:

  • 一元一阶类型构造函数是 * -> *(它采用单一类型并生成最终类型,例如 Set)
  • binary first-order type constructor is * -> * -> * (a binary type constructor, takes two types to produce the final type, e.g. Map)
  • 一元高级类型是 (* -> *) -> *(采用单个一元类型构造函数来生成最终类型,例如 Monad)

等等

因此,一阶类型采用 simple/concrete/proper 类型并生成最终类型,而更高种类的类型则高出一个级别;它需要一个一阶类型来产生最终类型。

编辑:

在 "edit" 部分回答您的问题:好的,我想我知道是什么让您感到困惑。 listMonoid 不是类型,所以它不可能是更高级的类型。这是一种方法。 Monad[List[Int]] 是完全解析的类型。 Monad[F[A]]也完全解决了。但是,Monad本身就是高阶类型。

让我把并行函数拉出来。如果您有一个函数 foo(x: Int),那么 foo(42)foo(someIntegerValue) 等函数调用会产生具体值。这些类似于 Monad[List[Int]]Monad[F[A]]。然而,foo 本身是一个函数,就像 Monad 本身是一个类型构造函数一样。

如果foo取简单值(不是函数),则为一阶函数;如果它接受或 returns 一个函数,那么它就是一个高阶函数。与类型构造函数相同。如果它采用简单类型,则它是一阶类型构造函数。示例:List。如果它采用另一个类型构造函数,则它是高阶类型构造函数(也称为高种类类型)。示例:Monad.

不要将已解析的类型与类型构造函数混合使用。思考函数 foo 是否高阶是有意义的;这取决于它的参数和 return 类型。但是考虑 foo(42) 是否为高阶是没有意义的;这不是一个功能,而是一个功能应用程序,它会产生价值。 Monad[List[Int]] 不是类型构造函数,而是类型构造函数 List 对类型构造函数 Monad (高阶)的应用。同样,Monoid[List[Int]] 不是类型构造器,而是类型 List[Int] 对类型构造器 Monoid 的应用(一阶)。 高阶类型构造函数 称为 HKT。谈论 HKT 并指出具体的已解析类型(由于应用某种类型构造函数而创建)是没有意义的。