我正在阅读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吗?
答案 0 :(得分:6)
一些术语:
当你说
时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
在类级别上并不真正关心“内部类型”本身,因为它将由方法Monad
和op
定义。你也可以说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并指出具体解决的类型(由于应用某种类型的构造函数而创建)是没有意义的。