Scalaの上位の型とは何ですか?


275

あなたはウェブ上で以下を見つけることができます:

  1. より高い種類の型==型コンストラクタ?

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

    定義に準拠する型を抽象化するため、これはより高い種類の型であると言う人もいます。

    上位の種類は、他の型を取り、新しい型を構築する型です

    これらはタイプコンストラクターとも呼ばれます。(たとえば、Scalaでのプログラミング)。

  2. より高い種類の型==型コンストラクターを型パラメーターとして受け取る型コンストラクター?

    論文Generics of a Higher Kindで、あなたは読むことができます

    ...タイプを抽象化するタイプを抽象化するタイプ(「より種類の高いタイプ」)... "

    それはそれを示唆しています

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

    より親切なタイプです。

したがって、これを念頭に置いて、型コンストラクタより高い種類の型、および型コンストラクタを型パラメータとして取る型コンストラクタを区別することは困難です。したがって、上記の質問です。


例としてランデイのファンクターを追加しました。
Lutz

回答:


284

いくつかの曖昧さをなくして、この混乱のいくつかを開始することを補います。人々はそれに慣れている傾向があるので、私はこれを説明するために値レベルのアナロジーを使用するのが好きです。

型コンストラクターは、型を「構築」するために型引数に適用できる型です。

値コンストラクターは、値を「構築」するために値引数に適用できる値です。

値コンストラクタは通常「関数」または「メソッド」と呼ばれます。これらの「コンストラクター」は「ポリモーフィック」(さまざまな「形状」の「もの」を作成するために使用できるため)、または「抽象化」(異なるポリモーフィックインスタンス間で異なるものを抽象化するため)とも呼ばれます。

抽象化/多態性のコンテキストでは、1次は抽象化の「単一使用」を指します。型を一度抽象化しますが、その型自体は何も抽象化できません。Java 5ジェネリックは一次です。

上記の抽象化の特徴付けの一次解釈は次のとおりです。

型コンストラクタは、適切な型引数に適用して適切な型を「構築」できる型です。

値コンストラクターは、適切な値を「構築」するために適切な値引数に適用できる値です。

1や型などの抽象化(これを「ゼロ次」と呼ぶことはできると思いますが、これがどこで使用されたかはStringわかりません)がないことを強調するには、通常、何かが「適切な」値または型であると言います。

適切な値は、引数を待機していないという意味で「すぐに使用可能」です(引数を抽象化しません)。それらは、簡単に印刷/検査できる値と考えてください(関数のシリアル化は不正です!)。

適切なタイプとは、値(値コンストラクターを含む)を分類するタイプであり、タイプコンストラクターは値を分類しません(適切なタイプを生成するには、最初に適切なタイプ引数に適用する必要があります)。タイプをインスタンス化するには、適切なタイプである必要があります(ただし十分ではありません)。(それは抽象クラスか、アクセスできないクラスかもしれません。)

「高次」とは、単に多形性/抽象化を繰り返し使用することを意味する一般的な用語です。これは、ポリモーフィックタイプと値についても同じことを意味します。具体的には、高次の抽象化は、何かを抽象化するものを抽象化します。タイプの場合、「高次」という用語は、より一般的な「高次」の特別な目的のバージョンです。

したがって、特性評価の高次バージョンは次のようになります。

型コンストラクターは、型引数(適切な型または型コンストラクター)に適用して適切な型(コンストラクター)を「構築」できる型です。

値コンストラクターは、適切な値(コンストラクター)を「構築」するために値引数(適切な値または値コンストラクター)に適用できる値です。

したがって、「高次」とは、単に「Xを超えて抽象化する」と言ったときに、本当にそれを意味するということです。のX独自の「抽象化権」を失うことはありません以上の抽象化されている:それは抽象すべてのそれは望んでいます。(ちなみに、ここでは「abstract」という動詞を使用しています。値や型の定義に不可欠ではないものを除外することで、抽象化のユーザーが引数として変更/提供できるようにします。)

以下は、適切な1次および高次の値と型の例(電子メールによる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

私はそれをより高い家系として読み続け、家系の精神を想像します
Janac Meena

110

(この回答は、いくつかのグラフィカルな情報と歴史的な情報によってAdriaan Moorsの回答を装飾する試みです。)

より高い種類の型は、2.5以降のScalaの一部です。

  • その以前は、Scalaは、これまでのJavaと同様に、型コンストラクタ(Javaの「ジェネリック」)を型コンストラクタの型パラメータとして使用することを許可していませんでした。例えば

     trait Monad [M[_]]

    不可能でした。

    Scala 2.5では、より高いレベルでタイプを分類する機能(タイプコンストラクターポリモーフィズムと呼ばれる)によってタイプシステムが拡張されました。これらの分類は種類と呼ばれます。

    タイプと種類の領域、「Generics of a Higher Kind」から**派生**Generics of a Higher Kindから派生した画像)

    その結果、型コンストラクター(たとえばList)は、型コンストラクターの型パラメーターの位置で他の型と同じように使用できるため、Scala 2.5以降、最初のクラス型になりました。(Scalaのファーストクラスの値である関数と同様)。

    より高い種類をサポートするタイプ・システムの文脈において、我々は区別することができる適切なタイプ、等のタイプInt又はList[Int]一次のようなタイプからList高い種類のタイプのようなFunctor、またはMonad(タイプにわたる抽象型上抽象タイプ)。

    一方、Javaの型システムは種類をサポートしていないため、「上位の種類」の型はありません。

    したがって、これは、サポートしている型システムの背景に対して見なければなりません。

  • Scalaの場合、次のような型コンストラクタの例がよく見られます

     trait Iterable[A, Container[_]]

    見出しが「より高い種類の型」の場合(例:汎用プログラマー向けのScala、セクション4.3)

    多くの場合Containerより高い種類の型呼ばれ、とは区別されないため、これは誤解を招く場合がありますが、Iterableより正確には、

    Containerここでは、より高い種類(高次)の型のコンストラクターパラメーターとしての使用Iterable


80

種類普通のようなタイプのIntCharインスタンスの値であるが、あります*。のような単項型コンストラクタの種類は次のとおりMaybeです* -> *。バイナリ型コンストラクタのようなEitherカリー化)種類* -> * -> *など。あなたは次のようなタイプを表示することができますMaybeし、Either彼らは1つまたは複数のタイプを取り、型を返す:タイプレベルの関数として。

関数である高次それが持っている場合次数が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の例は何でしょうか?ランデイのファンクターは最初のカテゴリーに当てはまるのでしょうか?
Lutz

1
@lutz:最初のカテゴリに含まれます:型コンストラクターからFunctor適切な型(まあ、特性ですが同じアイデア)Functor[F[_]]を生成しますF
Jon Purdy

1
@ジョン:非常に洞察に満ちた投稿、ありがとうございます。型コンバーター(* => *) => (* => *)はScalaで表現できますか?そうでない場合、他の言語で?
Eugen Labun

@JonPurdyカレーとの比較* ⇒ * ⇒ *は非常に役立ちます。ありがとう!
Lifu Huang

(* ⇒ *) ⇒ (* ⇒ *)スペルも可能(* ⇒ *) ⇒ * ⇒ *です。Scalaではのように表現できますFoo[F[_], T]。これは、(Haskellで)のようなタイプnewtype Twice f a = Twice (f (f a))(例:Twice Maybe IntMaybe (Maybe Int)Twice [] Char[[Char]])または無料のモナドのようなより興味深いタイプdata Free f a = Pure a | Free (f (Free f a))です。
Jon Purdy

37

私は言うだろう:より高い種類の型、型コンストラクタよりも抽象的です。例えば考慮

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

ここにFunctor「より高い種類のタイプ」があります(「Generics of a Higher Kind」の論文で使用されています)。これは、(List適切な型のみを抽象化する)のような具体的な(「1次」)型コンストラクタではありません。すべての単項(「一次」)型コンストラクター(で示される)を抽象化しますF[_]

または別の言い方をすると、Javaでは型コンストラクター(例List<T>:)は明確にありますが、それらを抽象化できないため(たとえば、Functor上記で定義されたインターフェイスを記述できないため)、「より高い種類の型」はありません。少なくとも直接ではない)。

「高次(タイプコンストラクター)ポリモーフィズム」という用語は、「より高い種類の型」をサポートするシステムを表すために使用されます。


これは私が考えたものですが、「具体的な型コンストラクタ」はすでに「より高い種類の型」であるジョンの答えに矛盾しているようです。
Lutz

3
はい。ジョンの回答によると(私が理解しているように)List<T>、Javaは明らかに種類を持っているので、単項型コンストラクタになります* -> *。Jonの答えに欠けているのは、*それをより高い種類の型と呼ぶために、「全体」(Javaのように2番目だけではなく)を抽象化できなければならないということです。
ランデイ

@Landai:紙汎用プログラマーのためのScala(イテレータ又は容器が意図されている場合、それは明らかではないが)セクション4.3で形質のIterableを示唆している[A、コンテナ[_]]はここで他の側に高kinded型にvero690でセクション2.3.1では、(*-> *)-> *(高次の型コンストラクターでパラメーター化された型演算子)などのイタレーターまたはFunctorトレイトに似た、より種類の高い型コンストラクターを使用しています。
Lutz

1
これはおそらく正しいですが、ここでヘアを分割し始めていると思います。より高い種類の型に関する重要な点は、型コンストラクターが関係する(1つの型のコンストラクターのポリモーフィズムを順序付ける)だけでなく、その型コンストラクターの具象型を抽象化できる(より高い順序の型コンストラクターのポリモーフィズム)ことです。制限なしで(型と型コンストラクタに関して)必要なものを何でも抽象化できるため、その機能のすべての可能なバージョンに名前を付けることはあまり面白くありません。そしてそれは私の脳を痛めます。
ランデイ

2
一般に、ここでは定義と参照を区別することが重要です。定義def succ(x: Int) = x+1は「値コンストラクタ」を紹介します(これの意味については、他の回答を参照してください)succ(この値をsucc(x:Int)と呼ぶ人はいません)。類推すると、Functorは回答で定義された(実際にはより種類の高い)タイプです。ここでも、あなたのようにそれを参照するべきではありませんFunctor[F[_]](何であるかF、何がある?_彼らがスコープ内にないよ、残念ながら、領海ここにすることによりexistentialsのmuddiesのための糖衣構文?!F[_]ショート用F[T forSome {type T}]
アドリアンムーアズ

1

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私はそれが価値がその全体(スカラ座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.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.