型理論の正しい用語:型、型コンストラクタ、種類/並べ替え、値


14

前の質問への回答では、特定の構成体の正しい用語について小さな議論が始まりました。私は(以外の質問見つからなかったので、このまたはその明確にこの問題に対処するため、非常に正しいことではない、)、私はこの新しいものを作っています。

疑わしい用語とその関係は、type、type constructor、type parameter、kinds or sorts、およびvaluesです。

また、ウィキペディアで型理論を確認しましたが、それでもそれほど明確にはなりませんでした。

したがって、適切な参照回答を得るために、自分の理解を確認するために:

  • これらのことはどのように適切に定義されていますか?
  • これらのそれぞれの違いは何ですか?
  • それらは互いにどのように関連していますか?

回答:


13

さて、一つずつ行きましょう。

値は、プログラムが評価して調整する具体的なデータです。派手なものは何もありません、いくつかの例は

  • 1
  • true
  • "fizz buzz foo bar"

タイプ

型のわかりやすい説明は、「値の分類子」です。型は、実行時にその値がどうなるかについての少しの情報ですが、コンパイル時に示されます。

たとえばe : bool、コンパイル時に、それeが実行時trueまたはfalse実行中であることを知っている場合、他に何もありません!型は値をこのようにうまく分類するため、この情報を使用してプログラムのいくつかの基本的なプロパティを決定できます。

たとえば、あなたがいつ、そしてを追加するのeを見たなら、何かが少しずれていることがわかります!実際、これにフラグを立てて、コンパイル時にエラーを投げることができます。「ねえ、それはまったく意味がありません!」e'e : inte' : String

より強力な型システムにより、より興味深い値を分類する、より興味深い型が可能になります。たとえば、いくつかの機能を考えてみましょう

f = fun x -> x

それはかなり明確ですがf : Something -> Something、それは何Somethingでしょうか?退屈な型システムでは、のような任意のものを指定する必要がありますSomething = int。より柔軟な型システムでは、次のように言えます

f : forall a. a -> a

つまりa、「いずれの場合も、にfマッピングaするa」ということです。これにより、fより一般的に使用して、より興味深いプログラムを作成できます。

さらに、コンパイラは、指定した分類子を実際に満たすかどうかをチェックしf = fun x -> trueます。バグがある場合、コンパイラはそう言います!

tldrとして; 型は、実行時に式が持つことができる値に対するコンパイル時の制約です。

型コンストラクタ

いくつかのタイプは関連しています。たとえば、整数のリストは文字列のリストに非常に似ています。これはsort、整数の場合がsort文字列の場合とほとんど同じです。それらの違いを一般化し、要求に応じて構築することにより、これらのほぼ同じタイプを構築する一種の工場を想像できます。それが型コンストラクターです。型から型への関数のようなものですが、もう少し制限があります。

古典的な例は一般的なリストです。の型コンストラクタは単なる一般的な定義です

 data List a = Cons a (List a) | Nil

これListは、型aをその型の値のリストにマップする関数です!Javaランドでは、これらはおそらく「ジェネリッククラス」と呼ばれていると思います

型パラメーター

型パラメーターは、型コンストラクター(または関数)に渡される型です。値レベルと同じように、型パラメーターを持つ方法と同じようにfoo(a)パラメーターがあると言います。aList aa

種類

種類は少し難しいです。基本的な考え方は、特定のタイプが似ているということです。たとえば、java 、... にはすべてのプリミティブ型がintありcharfloatこれらはすべて同じ「型」を持つように動作します。例外として、型自体の分類子については、分類子を種類と呼びます。ですからint : PrimString : BoxList : Boxed -> Boxed

このシステムは、型が値を管理する方法と同様に、どのような種類の型をどこで使用できるかについて、すばらしい具体的なルールを提供します。言うのは明らかにナンセンスだ

 List<List>

または

 List<int>

Javaでは、Listそのように使用される具体的な型に適用する必要があるためです!それらの種類List : Boxed -> Boxedとを見てみるとBoxed -> Boxed /= Boxed、上記は種類エラーです!

ほとんどの場合、種類についてはあまり考えず、単にそれらを「常識」として扱いますが、より洗練された型システムでは、考えることが重要です。

これまで私が言ってきたことの小さなイラスト

 value   : type : kind  : ...
 true    : bool : Prim  : ...
 new F() : Foo  : Boxed : ...

ウィキペディアよりも良い読書

この種のことに興味があるなら、良い教科書に投資することを強くお勧めします。一般に、型理論とPLTは非常に広大であり、一貫した知識ベースがなければ、あなた(または少なくとも私)は何ヶ月も何処にも行かずに歩き回ることができます。

私の好きな本の2つは

  • 型とプログラミング言語-Ben Pierce
  • プログラミング言語の実用的な基礎-ボブ・ハーパー

どちらも私が今話したことを紹介する優れた本であり、さらに美しく、詳細に説明された詳細です。


1
タイプはセットですか?私は「分類子」の方が好きですが、これが何を意味するのかを説明しません。また、型が何であるかをよく理解しないと、答えの残りの部分が落ちます。
ロバートハーヴェイ14

@RobertHarveyどのように見えるのか、セットに関するすべての言及を削除しました:)
ダニエル・グラッツァー14

1
はるかに良い....
ロバートハーヴェイ14

@RobertHarveyセットとしての型のビューは非常に直感的です。たとえばint、Java の型は2 ^ 64個の異なる値のセットで構成されます。セットとの類推はサブタイプが関与するときに壊れますが、特に代数データ型を考慮すると、それは十分な初期の直観です(たとえば、2つのタイプのユニオンはいずれかのタイプのメンバーのいずれかを含むことができます;それらのセットのユニオンです) 。
ドーバル14

@Doval:顧客を説明するクラスを記述する場合、インスタンスのコレクションを作成するため、顧客の「セット」を表す可能性があります。しかし、顧客の「セット」を記述するために顧客がタイプであると言うことはトートロジーです。当たり前のようです。さらに興味深いのは、顧客タイプが顧客の特性を記述することです。これを説明するために「セット」を使用すると、実際よりも抽象的なように見えます。おそらく、あなたは数学者でない限り。
ロバートハーヴェイ14

2

これらのことはどのように適切に定義されていますか?

それらは、厳格で学術的な数学的裏付けによって適切に定義されており、それらが何であるか、どのように機能するか、何が保証されているかについて強力な主張を提供します。

しかし、プログラマーはほとんどそれを知る必要はありません。彼らは概念を理解する必要があります。

すべてがそこから構築されるため、値から始めましょう。値は、計算で使用されるデータです。アプローチにもよりますが、これらは誰もがよく知っている値です。42、3.14、「How now brown cow」、経理部門でのジェニーの人事記録など。

値の他の解釈は記号です。ほとんどのプログラマは、これらのシンボルが列挙の「値」であることを理解しています。LeftおよびRight列挙型のシンボルですHandedness(両手利きの人や魚は無視します)。

実装に関係なく、値は言語が計算を実行するために使用するさまざまなものです。

タイプ

値の問題は、すべての値に対してすべての計算が有効ではないことです。42 + goat本当に意味がありません。

これは、型が作用する場所です。タイプは、値のサブセットを定義するメタデータです。上記のHandedness列挙は良い例です。このタイプは、「だけ言うLeftと、Rightここで使用することができます」。これにより、プログラムは特定の操作がエラーになることを非常に早く判断できます。

考慮すべきもう1つの実用的な方法は、内部ではコンピューターがバイトで動作することです。バイト42は数字42を意味する場合もあれば、文字*を意味する場合もあれば、会計担当のジェニーを意味する場合もあります。また、型は(実際に使用されるものであり、理論的なものではありません)、コンピューターで使用される基本的なバイトのコレクションのエンコードを定義するのに役立ちます。

種類

そして、ここから少し出かけ始めます。それでは、プログラミング言語に型を参照する変数がある場合、どの型がありますか?

たとえば、JavaとC#の場合、型がありますType(typeがありType、...がずっと続きます)。これは種類の背後にある概念です。一部の言語では、Type変数を使用すると、JavaやC#よりも少し便利なことができます。それが起こったら、「タイプであるが、ある種の値が欲しい」と言うのが便利になりますIEnumerable<int>。多田!種類。

ほとんどのプログラマーは、JavaやC#の一般的な制約のような種類を考えることができます。検討してくださいpublic class Foo<T> where T: IComparable{}。種類のある言語では、T: kindOf(IComparable)変数宣言は有効になります。クラスや関数の宣言でできる特別なことだけではありません。

型コンストラクタ

おそらく驚くことではないが、型コンストラクターは単に型のコンストラクターです。「しかし、どのように型を構築するのですか?型はただです。」ええ…そんなにありません。

また、当然のことながら、コンピュータープログラムが使用するさまざまな有用な値のサブセットをすべて構築することは非常に困難です。型コンストラクタは、プログラマがこれらのサブセットを意味のある方法で「構築」できるように機能します。

型コンストラクタの最も一般的な例は、配列定義ですint[4]。ここ4では、値を使用intして4つのエントリを持つsの配列を作成する型コンストラクターを指定しています。別の入力タイプを指定した場合、異なる出力タイプが得られます。

ジェネリックは別の型のコンストラクターであり、別の型を入力として受け取ります。

多くの言語には、type P -> Rを受け取ってtype Pを返す関数を表す型を構築するような型コンストラクタがありますR

これで、コンテキストは「型を返す関数」が型コンストラクタかどうかを判断します。私の(確かに限られた)経験では、行は「コンパイル時にこのタイプを使用できますか?」です。はい?型コンストラクタ。番号?ただの機能。

型パラメータ

型コンストラクタに渡されたパラメータを覚えていますか?型コンストラクタの一般的な形式であるため、これらは一般的に、型パラメータとして知られていますType[param]Type<param>


1
「種類」に関するセクションを明確化/拡張してもらえますか?Haskellでは、型にはkind *があり、型コンストラクタ(引数が1つ)にはkindがあり* -> *ます。(Num a) => a(「タイプクラスのaインスタンスである任意のタイプ」を意味する)などの制約Num自体は種類ではありません。タイプクラスNum自体は「種類」ではありませんが、種類があり* -> Constraintます。Haskellの「種類」の考え方(型理論の種類に密接に関連していると思いますか)を、あなたが与える例に関連付けるのは難しいと思います。
ジョンバーソロミュー

私はGHCiのの、言うべき:kindコマンドは、一種の与えNumとしては* -> Constraint。それはGHCに特有のものかもしれません、私にはわかりません。
ジョンバーソロミュー14

@JohnBartholomew-Haskell Kindsは、「タイプコンストラクターのシグネチャ」に近いものです。残念ながら、私のHaskellは、その詳細についてあまりにも多くのことを話すのに満足できるほどには近づいていません。
テラスティン14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.