Scala中什么是更高种类的类型?


275

您可以在网上找到以下内容:

  1. 更高种类的类型==类型构造函数?

    class AClass[T]{...} // For example, class List[T]

    有人说这是一种更高种类的类型,因为它抽象了符合该定义的类型。

    较高种类的类型是采用其他类型并构造新类型的类型

    这些虽然也称为类型构造函数。(例如,在Scala编程中)。

  2. 更高种类的类型==类型构造函数,它将类型构造函数作为类型参数?

    高级类属的论文,您可以阅读

    ...在类型上进行抽象的类型,在类型上进行抽象(“高级类型”)...”

    这表明

    class XClass[M[T]]{...} // or
    
    trait YTrait[N[_]]{...} // e.g. trait Functor[F[_]]
    

    是一种较高的类型。

因此,考虑到这一点,很难区分类型构造函数更高种类的类型将类型构造函数作为类型参数的类型构造函数,因此存在上述问题。


以Landei的Functor为例。
Lutz

Answers:


284

让我通过消除歧义消除一些混乱。我喜欢用价值水平的类比来解释这一点,因为人们往往更熟悉它。

类型构造函数是一种类型,您可以将其应用于类型参数以“构造”一个​​类型。

值构造函数是一个值,您可以将其应用于值参数以“构造”值。

值构造函数通常称为“函数”或“方法”。这些“构造函数”也被称为“多态的”(因为它们可用于构造变化的“形状”的“东西”)或“抽象”(因为它们抽象化了不同的多态实例之间的变化)。

在抽象/多态性的上下文中,一阶是指抽象的“单次使用”:您一次对某个类型进行了抽象,但是该类型本身无法对任何事物进行抽象。Java 5泛型是一阶的。

上述抽象特征的一阶解释是:

类型构造函数是一种类型,您可以将其应用于适当的类型参数以“构造”适当的类型。

值构造函数是一个值,您可以将其应用于适当的值参数以“构造”适当的值。

为了强调不涉及任何抽象(我想您可以称其为“零阶”,但我从未见过在任何地方使用过这种抽象),例如value 1或type String,我们通常说某种东西是“ proper”值或type。

适当的值在某种意义上是“立即可用的”,因为它不等待参数(它不会抽象化它们)。可以将它们视为可以轻松打印/检查的值(序列化功能就是作弊!)。

适当的类型是对值进行分类的类型(包括值构造函数),类型构造函数不对任何值进行分类(首先需要将它们应用于正确的类型参数以产生适当的类型)。要实例化一个类型,有必要(但不足以满足)是一个适当的类型。(它可能是抽象类,也可能是您无权访问的类。)

“高阶”只是一个通用术语,表示重复使用多态性/抽象。对于多态类型和值,这意味着同一件事。具体而言,高阶抽象是对某物的抽象,而某物是对某物的抽象。对于类型,术语“高级”是更通用的“高级”的专用版本。

因此,我们表征的高阶版本变为:

类型构造函数是一种类型,您可以将其应用于类型实参(适当的类型或类型构造函数)以“构造”适当的类型(构造函数)。

值构造函数是一个值,您可以将其应用于值参数(适当的值或值构造函数)以“构造”适当的值(构造函数)。

因此,“高阶”只是意味着当您说“抽象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}



5
Adriaan的“类型构造函数多态”文章现在在adriaanm.github.com/research/2010/10/06/…–
Steven Shaw

我一直以较高的
血统

110

(此答案是通过一些图形和历史信息来修饰Adriaan Moors答案的尝试。)

从2.5开始,更高种类的类型是Scala的一部分。

  • 在此之前,Scala直到现在仍像Java一样,不允许将类型构造函数(Java中的“泛型”)用作类型构造函数的类型参数。例如

     trait Monad [M[_]]

    不可能的。

    在Scala 2.5中,类型系统已通过在更高级别上对类型进行分类的能力得到扩展(称为类型构造函数多态性)。这些分类称为种类。

    类型和种类表示,源自“高级泛型” (图片来自高级泛型

    结果是,类型构造函数(例如List)可以像其他类型一样在类型构造函数的类型参数位置使用,因此自Scala 2.5起,它们成为第一类类型。(类似于Scala中一流的函数)。

    在一种类型的系统中支持更高种上下文中,我们可以区分合适类型,种类等IntList[Int]从第一阶类型,如List类型更高的种FunctorMonad(类型的抽象以上类型的抽象以上类型)。

    另一方面,Java的类型系统不支持种类,因此没有“高级种类”的类型。

    因此,必须在支持类型系统的背景下才能看到这一点。

  • 对于Scala,您经常会看到类型构造器的示例,例如

     trait Iterable[A, Container[_]]

    标题为“更高种类的类型”,例如在Scala中,针对通用程序员,第4.3节

    这有时missleading,因为很多是指Container提高kinded类型,而不是Iterable,但更精确的是,

    在此使用Container类型较高的类型(较高阶)的类型构造函数参数Iterable


80

普通类型,如IntChar,其实例是价值观,是*。一元类型构造器的类型Maybe* -> *; 二进制类型的构造函数,例如Eitherhave(curried)kind * -> * -> *,等等。您可以像MaybeEither作为类型级别的函数一样查看类型:它们接受一个或多个类型,然后返回一个类型。

如果函数的阶数大于1,则该函数为高阶函数,其中该阶数(非正式地)是函数箭头的嵌套深度:

  • 订单0: 1 :: Int
  • 顺序1: chr :: Int -> Char
  • 顺序2 :fix :: (a -> a) -> amap :: (a -> b) -> [a] -> [b]
  • 顺序3: ((A -> B) -> C) -> D
  • 订单4: (((A -> B) -> C) -> D) -> E

因此,长话短说,种类繁多的类型只是类型级别的高阶函数。

  • 订单0: Int :: *
  • 顺序1: Maybe :: * -> *
  • 顺序2:Functor :: (* -> *) -> Constraint—种类较多:将一元类型构造函数转换为类型限制

好的,我知道了,那么在(Scala)中(*⇒*)⇒*和(*⇒*)⇒(*⇒*)的例子是什么?Landei的Functor是适合第一类还是更适合第二类?
Lutz

1
@lutz:属于第一类:从类型构造函数Functor产生适当的类型(嗯,特质,但想法相同)。Functor[F[_]]F
乔恩·普迪

1
@Jon:非常有见地的帖子,谢谢。可以(* => *) => (* => *)在Scala中表达类型转换器吗?如果没有,用任何其他语言?
Eugen Labun 2012年

@JonPurdy * ⇒ * ⇒ *与currying 之间的比较非常有帮助。谢谢!
Lifu Huang

(* ⇒ *) ⇒ (* ⇒ *)也可以拼写(* ⇒ *) ⇒ * ⇒ *。它可以用Scala表示Foo[F[_], T]。这种类型的类型newtype Twice f a = Twice (f (f a))(例如,在Haskell中)(例如Twice Maybe IntMaybe (Maybe Int)Twice [] Char[[Char]])或更有趣的类型(例如自由monad)data Free f a = Pure a | Free (f (Free f a))
乔恩·普迪

37

我会说:更高种类的类型类型构造函数抽象。例如考虑

trait Functor [F[_]] {
   def map[A,B] (fn: A=>B)(fa: F[A]): F[B]
}

Functor是“更高种类的类型”(如“更高种类的泛型 ”中所使用)。它不是一个具体的(“一阶”)类型构造函数List(仅对适当的类型进行抽象)。它抽象了所有一元(“一阶”)类型的构造函数(用表示F[_])。

或者List<T>换一种说法:在Java中,我们显然有类型构造函数(例如),但是我们没有“更高种类的类型”,因为我们不能对它们进行抽象(例如,我们不能编写Functor上面定义的接口-至少不是直接)。

术语“高阶(类型构造函数)多态性”用于描述支持“高阶类型”的系统。


这就是我的想法,但似乎与Jon的答案相矛盾,在这里Jon的“具体类型构造函数”已经是“更高种类的类型”。
卢兹(Lutz)

3
是。根据乔恩(Jon)的回答(据我所知)List<T>,Java显然是那种一元类型的构造函数* -> *。Jon的答案缺少的是,您必须能够对“整体”(而不是*像Java中那样仅对第二件事)进行抽象,以便将其称为更高种类的类型。
Landei 2011年

@Landai:第4.3节中针对通用程序员的Scala论文建议,特质Iterable [A,Container [_]]是一种类型较高的类型(尽管尚不清楚是要使用Iterator还是Container),另一方面是vero690中第2.3.1节使用术语更高种类的类型构造函数来表示某种东西,例如(*-> *)-> *(使用高阶类型构造函数进行参数化的类型运算符),其外观类似于Iterator或Functor特性。
卢兹(Lutz)

1
这可能是正确的,但是我认为我们开始在这里分裂头发。关于更高种类的类型的重要一点是,不仅涉及类型构造函数(一种类型的构造函数多态性),而且我们能够抽象出该类型构造函数的具体类型(更高阶的类型构造函数多态性)。我们可以不受限制地抽象我们想要的任何东西(关于类型和类型构造函数),这使得命名该功能的所有可能版本变得不那么有趣。而且它伤害了我的大脑。
兰代2011年

2
通常,在此处区分定义和参考很重要。该定义def succ(x: Int) = x+1引入了“值构造函数”(请参阅​​我的其他答案以了解我的意思)succ(没人会将此值称为succ(x:Int))。以此类推,Functor是您的答案中定义的(实际上是较高种的)类型。同样,您不应该将其称为Functor[F[_]](什么是F?什么是_?它们不在范围内!不幸的是,存在主义者的句法糖通过F[_]简写来混淆了这里的内容F[T forSome {type T}]
Adriaan Moors

0

Scala REPL提供:kind命令

scala> :help kind

:kind [-v] <type>
Displays the kind of a given type.

例如,

scala> trait Foo[A]
trait Foo

scala> trait Bar[F[_]]
trait Bar

scala> :kind -v Foo
Foo's kind is F[A]
* -> *
This is a type constructor: a 1st-order-kinded type.

scala> :kind -v Foo[Int]
Foo[Int]'s kind is A
*
This is a proper type.

scala> :kind -v Bar
Bar's kind is X[F[A]]
(* -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.

scala> :kind -v Bar[Foo]
Bar[Foo]'s kind is A
*
This is a proper type.

这些:help提供了明确的定义,因此我认为值得将其完整发布在此处(Scala 2.13.2)

scala> :help kind

:kind [-v] <type>
Displays the kind of a given type.

    -v      Displays verbose info.

"Kind" is a word used to classify types and type constructors
according to their level of abstractness.

Concrete, fully specified types such as `Int` and `Option[Int]`
are called "proper types" and denoted as `A` using Scala
notation, or with the `*` symbol.

    scala> :kind Option[Int]
    Option[Int]'s kind is A

In the above, `Option` is an example of a first-order type
constructor, which is denoted as `F[A]` using Scala notation, or
* -> * using the star notation. `:kind` also includes variance
information in its output, so if we ask for the kind of `Option`,
we actually see `F[+A]`:

    scala> :k -v Option
    Option's kind is F[+A]
    * -(+)-> *
    This is a type constructor: a 1st-order-kinded type.

When you have more complicated types, `:kind` can be used to find
out what you need to pass in.

    scala> trait ~>[-F1[_], +F2[_]] {}
    scala> :kind ~>
    ~>'s kind is X[-F1[A1],+F2[A2]]

This shows that `~>` accepts something of `F[A]` kind, such as
`List` or `Vector`. It's an example of a type constructor that
abstracts over type constructors, also known as a higher-order
type constructor or a higher-kinded type.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.