私はすでにウィキペディアの記事を読み、明らかな場所を検索しましたが、行き詰まっています。Kind とは何かを簡単に教えてもらえますか? それは何のために使用されますか?
Scalaの例は最も高く評価されています
私はすでにウィキペディアの記事を読み、明らかな場所を検索しましたが、行き詰まっています。Kind とは何かを簡単に教えてもらえますか? それは何のために使用されますか?
Scalaの例は最も高く評価されています
要するに、種類は型に対するものであり、型は値に対するものです。
値とは 1
、2
、3
は値です。"Hello"
と"World"
、 、true
なども同様false
です。
値はタイプに属します。タイプは一連の値を記述します。1
、タイプ、タイプ、タイプ2
に3
属します。Nat
"Hello"
"World"
Text
true
false
Boolean
関数は引数として 1 つ以上の値を取り、結果として 1 つ以上の値を生成します。引数で意味のあることを行うために、関数はそれらについていくつかの仮定を行う必要があります。これは、それらの型を制約することによって行われます。そのため、通常、関数のパラメーターと戻り値にも型があります。
ここで、関数には型もあり、その入力と出力の型によって記述されます。たとえば、abs
数値の絶対値を計算する関数の型は
Number -> NonNegativeNumber
add
2 つの数値を加算する関数は、次の型を持ちます。
(Number, Number) -> Number
関数divmod
には型があります
(Number, Number) -> (Number, Number)
わかりましたが、関数が引数として値を取り、結果として値を生成し、関数が値である場合、関数は引数として関数を取り、結果として関数を返すこともできますよね? そのような関数のタイプは何ですか?
findCrossing
他の関数 (数値の) が y 軸と交差する点を見つける関数があるとします。関数を引数として取り、結果として数値を生成します。
(Number -> Number) -> Number
または、makeAdder
数値を取り、それに特定の数値を追加する関数を生成する関数:
Number -> (Number -> Number)
そして、別の関数の導関数を計算する関数:
(Number -> Number) -> (Number -> Number)
ここで抽象化のレベルを見てみましょう。値は非常に具体的なものです。それが意味することはただ一つ。ここで抽象化のレベルを順序付けると、値の順序は 0 であると言えます。
関数、OTOH はより抽象的です。単一の関数が多くの異なる値を生成できます。したがって、順序は 1 です。
関数を返したり受け取ったりする関数はさらに抽象的です。多くの異なる値を生成できる多くの異なる関数を生成できます。注文2です。
一般に、次数が 1 より大きいものをすべて「高次」と呼びます。
さて、しかし種類はどうですか?1
、2
、などには型が"Hello"
あると上で述べました。false
しかし、型はNumber
何ですか?それともText
?それともBoolean
?
もちろん、そのタイプはType
です!この「型の型」をkindと呼びます。
そして、値から値を構築する関数を持つことができるように、型から型を構築する関数を持つことができます。これらの関数は、型コンストラクターと呼ばれます。
関数に型があるように、型コンストラクターにも型があります。たとえばList
、要素の型を取り、その要素のリスト型を生成する型コンストラクターには、種類があります。
Type -> Type
Map
キー型と値型を取り、マップ型を生成する型コンストラクターには種類があります
(Type, Type) -> Type
さて、類推を続けると、関数を引数として取る関数を持つことができるなら、型コンストラクタを引数として取る型コンストラクタも持つことができるでしょうか? もちろん!
例として、Functor
型コンストラクターがあります。型コンストラクターを取り、型を生成します。
(Type -> Type) -> Type
私たちがいつもType
ここに書いていることに注意してください。Number
上記では、Text
、などのさまざまなタイプがありましたBoolean
。ここでは、常にタイプの種類のみ、つまりType
. これは (警告、悪い駄洒落) と入力するのが面倒なので、Type
どこにでも書くのではなく、 と書くだけ*
です。つまりFunctor
、種類があります
(* -> *) -> *
そしてNumber
種類があります
*
類推を続けると、Number
、Text
およびその他すべての種類*
は次数 0 でList
あり、その他すべての種類* -> *
またはそれ以上のものは一般的(*, …) -> (*, …)
に次数 1 でFunctor
あり、すべての種類(* -> *) -> *
または(など) は次数 2 です。この場合を除いて、ランク* -> (* -> *)
と呼ぶこともあります。注文の代わりに。
order/rank 1 より上のものはすべて、higher -order、higher-rank、またはhigher-kindedと呼ばれます。
類推が明確になったことを願っています。型は値のセットを記述します。種類は、型のセットを表します。
余談ですが、私はカリー化を完全に無視しました。基本的に、カリー化とは、2 つの値を取る関数を、1 つの値を取り、もう 1 つの値を取る関数を返す関数に変換できることを意味します。これは、厳密に 1 つのパラメーターを持つ関数を処理するだけでよいことを意味し、言語がはるかに単純になります。
ただし、これは技術的に言えば、add
定義を混乱させている高階関数であることも意味します (関数を返すため)。
私がこれまでに見たカインド/ハイカインドの最も雄弁な説明は、Scala のコンテキストでもありますが、Daniel Spiewak の High Wizardry in the Land of Scalaです。多くのバージョンがあり、彼はこの講演を数回行いました。ここでは最も長いものを選択しましたが、すぐにググって他のものを見つけることができます。
このトークからの最も重要なメッセージは、まさに @Jörg W Mittag による回答です。
「種類は型であり、型は値である」
この主題に関するより理論的な見解の別の場所は、論文Generics of a Higher Kindで、やはり Scala のコンテキストにあります。