首页 文章

Scala中更高的键控类型[重复]

提问于
浏览
3

这个问题在这里已有答案:

我正在阅读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[_]] {
 ...
 ...
}

因此,可折叠的特性是根据书中较高的一种类型 . 我的问题是,Monoid [A]对我来说也适合'更高的kinded类型'定义,因为它可以采用List [A] . 我的理解是否正确?如果不是什么使更高的kinded类型在Scala中成为更高的kinded类型?

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

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

那么我的listMonoid函数是HKT吗?

1 回答

  • 5

    一些术语:

    • 正确类型(例如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"参数化)参数化的抽象是更高级的类型 . 这是一个例子:

    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 在类级别上并不真正关心"inner type"本身,因为它将由方法 opzero 定义 . 您也可以在类 ListMonad 的定义点上说 trait Monad[M[A]] 和"fix"类型A(例如将其修复为Int),但是您失去灵活性(您的 ListMonad 将只能构造和平面图 List[Int] 并且您需要例如, List[String] )的另一个类 .

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

    它是一种单向关系 - 如果你有一个简单的类型A,它代表任何类型的任何顺序,所以在这种情况下 List[Int] 可以作为一个非常好的 A (所以 List[Set[Option[Try[Int]]]] 也可以 . 但如果你有一阶输入M [A],你不能把它变成一个简单的具体类型,如Int . 它需要是一个类型构造函数.Monoid可以使用Ints,但是Monad不能; monad需要有一些"container",如 Option[_]Try[_]List[_]Set[_] 等 . 这就像子类型 - 香蕉可以作为水果,但水果不能作为香蕉 . 适当的类型可以是任何东西;一阶类型需要一种类型来 生产环境 一种类型;更高级的类型需要一个生成类型的一阶类型,依此类推 .

    它's also important to note that it'是一个一元类型的构造函数,意味着它只需要一种类型(不像例如Map需要两种类型) . 类型构造函数通常用星号和箭头表示:

    • 一元一阶类型构造函数是 * -> * (它采用单一类型并生成最终类型,例如Set)

    • 二进制一阶类型构造函数是 * -> * -> * (二进制类型构造函数,需要两种类型来生成最终类型,例如Map)

    • 一元高级类型是 (* -> *) -> * (采用单个一元类型构造函数来生成最终类型,例如Monad)

    等等

    因此,一阶类型采用简单/具体/适当的类型并产生最终类型,而高级类型采用上一级;它采用一阶类型来生成最终类型 .

    EDIT:

    在"edit"中回答你的问题:好的我想我知道你有什么困惑 . listMonoid 不是一个类型,所以它可以't be a higher-kinded type. It'是一个方法 . Monad[List[Int]] 是完全解析的类型 . Monad[F[A]] 也完全解决了 . 但是, Monad 本身是更高阶的类型 .

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

    如果 foo 采用简单值(不是函数),则's a first-order function; if it takes or returns a function, then it'是高阶函数 . 与类型构造函数相同 . 如果它采用简单类型,则它是一阶类型构造函数 . 示例: List . 如果它需要另一种类型的构造函数,它是一个更高阶的类型构造函数(也称为更高级的类型) . 示例: Monad .

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

相关问题