Scala中更高的键控类型

时间:2017-04-17 08:41:22

标签: scala higher-kinded-types monoids

我正在阅读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阅读了几页,我遇到了更高级别的类型'根据书中的任何类型,它本身是一种可以采取其他类型的类型。

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

所以特性Foldable是根据书中更高的一种类型。我的问题是,Monoid [A]对我来说也适合更高级的类型'定义,因为它可以采取列表[A]。我的理解是否正确?如果不是什么使更高的kinded类型在Scala中成为更高的kinded类型?

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

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

我的listMonoid函数是HKT吗?

1 个答案:

答案 0 :(得分:6)

一些术语:

  • 正确的类型(例如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)或参数化类型(例如{ {1}},甚至是List[Int])。这使List[Set[Map[Int, Int]]成为一阶类型。我们也可以说它是一个一元类型的构造函数 - 它需要一种类型来生成最终类型。

与Monoid不同,某些抽象(例如Monad)需要由类型构造函数进行参数化。 Int不再起作用了。它需要“某种类型而不能产生另一种类型”。由类型构造函数参数化的抽象(即,由“一阶类型”参数化)是更高级的类型。这是一个例子:

Monoid

所以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在类级别上并不真正关心“内部类型”本身,因为它将由方法Monadop定义。你也可以说zero并在类trait Monad[M[A]]的定义点“修复”类型A(例如将其修复为Int),但是你失去了灵活性(你的ListMonad会然后只能构建和平面映射ListMonad,你需要一个不同的类,比如List[Int])。

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

另请注意我如何说Monad需要一个一元类型的构造函数,这意味着它只需要一种类型(不像例如Map需要两种类型)。类型构造函数通常用星号和箭头表示:

  • 一元一阶类型构造函数是Monoid[Int](它采用单一类型并生成最终类型,例如Set)
  • 二进制一阶类型构造函数是* -> *(二元类型构造函数,需要两种类型来生成最终类型,例如Map)
  • 一元高阶类型是* -> * -> *(采用单一的一元类型构造函数来生成最终类型,例如Monad)

因此,一阶类型采用简单/具体/正确类型并生成最终类型,而高级类型采用上一级;它采用一阶类型来生成最终类型。

修改

在“编辑”部分回答你的问题:好的我想我知道你有什么困惑。 (* -> *) -> *不是类型,因此它不能是更高级的类型。这是一种方法。 listMonoid是完全解析的类型。 Monad[List[Int]]也已完全解决。但是,Monad[F[A]]本身是一种更高阶的类型。

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

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

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