- 値を2個取って値を返すことを考える。たとえば足し算
- 2+3 = 5 は、具体的な2と3を足して5を得る。この具体的な式で表されたものを「関数の具体的な行為」と呼ぶことにする
- x+y = z は、値xと値yとを足して値zを得る、という「この関数の抽象的な機能」を表していると考える
- 次のfaはA型の引数を2つ取って、A型を返す。ただし、返すのは必ずA1という値、という関数である
data A = A1 | A2
let fa :: A -> A -> A; fa = \ x -> \ y -> A1
-
- このfaが定めているのは、「関数の抽象的な機能」である。変数 x yを使って定義されているから、それとわかる
- では、型を引数にして、型を作ったときにはどうやっていただろうか?
data A =A1 | A2
data FA = FA1 A A| FA2 A A
let fa1 :: FA; fa1 = FA1 A1 A1
let pick1st :: FA -> A; pick1st (FA1 x y) = x
-
- 型FAを作るのに、「具体的な型であるA」を引数にしていた
- Aは確かに、「A型」という要素を取りまとめた抽象的なものだが、型A、型B…と、たくさんの型が集まってきて、その型の集合を考えるときには、型集合の具体的な要素にすぎなくて、data FA = FA1 A A | FA2 A A とやるのは、いちいち、「具体的な要素を使った 2 + 2, 2 * 3のような式」の羅列をしていることになる。小学校の算数のようだ。やはり中学校で習う変数にするには、「一段階、上に登る」必要がある
- 型変数を使って、「型の代数」をすることにする
- リスト型 [] を見る。
- :type で調べているのは、値の入っていない空のリストという具体的なものの型であって、それは何かの型tを要素としたリスト [t] である、と示されている
- :kind で調べているのは、[]と表記されるリスト型の特徴 (kind)である。
- * -> * というのは、二つの型変数を使って表されることを意味している。新しい型の作成には1つの型を取り入れる、ということ
- :info (の1行目)には、型変数 a を用いて、空のリストか、型aの要素と、型aを要素とするリストとの連結( (:)演算処理)でできるリストかのいずれかであることが示されている
Prelude Control.Arrow> :type []
[] :: [t]
Prelude Control.Arrow> :kind []
[] :: * -> *
Prelude Control.Arrow> :info []
data [] a = [] | a : [a]
-
-
- 自作の型Aの場合には、型を作るときに、型変数を引数でとっていないので、:kindの結果は単なる * である
- Int型も、data Int の定義行で、型変数を引数で取ってないないので、:kindの結果は単なる * である
Prelude Control.Arrow> :kind A
A :: *
Prelude Control.Arrow> :info A
data A = A1 | A2
Prelude Control.Arrow> :kind Int
Int :: *
Prelude Control.Arrow> :info Int
data Int = GHC.Types.I# GHC.Prim.Int#