なぜより高い種類が必要なのですか?


13

いくつかの言語は、(例えば、型パラメータを持つクラスおよび機能を可能にするList<T>場合T、任意のタイプであってもよいです)。たとえば、次のような関数を使用できます。

List<S> Function<S, T>(List<T> list)

ただし、一部の言語では、この概念を1レベル上に拡張して、署名付きの機能を使用できます。

K<S> Function<K<_>, S, T>(K<T> arg)

K<_>それ自体がそのような型である場合List<_>、型パラメーターがあります。この「部分型」は、型コンストラクターとして知られています。

私の質問は、なぜこの能力が必要なのですか?List<T>すべてList<T>がほぼ同じであるが、すべてK<_>が完全に異なる可能性があるため、次のような型を持つことは理にかなっています。共通の機能をまったく持たないOption<_>とを持つことができますList<_>


7
ここにいくつかの良い答えがあります:stackoverflow.com/questions/21170493/…–
itsbruce

3
@itsbruce特に、FunctorLuis Casillasの答えの例は非常に直感的です。何がList<T>Option<T>共通しているの?あなたが私に1つと機能T -> Sを与えるならば、私はあなたにList<S>またはを与えることができますOption<S>。彼らが共通しているもう一つのことはT、両方から価値を得ようとすることができるということです。
ドーバル

@Doval:前者はどうしますか?後者に関心がある限り、両方のタイプを実装させることで対処できると思いますIReadableHolder<T>
スーパーキャット

私は、彼らが実装する必要があります推測している@supercat IMappable<K<_>, T>方法でK<S> Map(Func<T, S> f)として実装し、IMappable<Option<_>, T>IMappable<List<_>, T>。したがってK<T> : IMappable<K<_>, T>、それを使用するには制約が必要です。
グレッグロス

1
キャストは適切なアナロジーではありません。型クラス(または同様の構成体)で行われるのは、指定された型がより高い種類の型を満たす方法を示すことです。これには通常、新しい関数を定義するか、どの既存の関数(またはScalaのようなOO言語の場合はメソッド)を使用できるかを示すことが含まれます。これが完了すると、上位の型で動作するように定義された関数はすべてその型で動作します。しかし、関数/メソッドシグネチャの単純なセット以上が定義されているため、インターフェイス以上のものです。私は、それがどのように機能するかを示すために答えを書きに行かなければならないと思う。
-itsbruce

回答:


5

他の誰も質問に答えていないので、私は自分でやってみようと思います。私は少し哲学を取得する必要があります。

ジェネリックプログラミングは、型情報を失うことなく、同様の型を抽象化することです(これはオブジェクト指向の値多態性で起こります)。これを行うには、使用できるインターフェイス(OOの用語ではなく、一連の操作)を必ず共有する必要があります。

オブジェクト指向言語では、型はクラスのおかげでインターフェースを満たします。各クラスには、その型の一部として定義された独自のインターフェイスがあります。すべてのクラスList<T>が同じインターフェースを共有しているため、T選択に関係なく機能するコードを作成できます。インターフェイスを課すもう1つの方法は、継承の制約です。この2つは異なっているように見えますが、考えてみると似ています。

ほとんどのオブジェクト指向言語でList<>は、それ自体は適切な型ではありません。メソッドがないため、インターフェイスがありません。List<T>これらのものがあるのはそれだけです。基本的に、より技術的な用語では、意味のある抽象化できる型はkindを持つ型のみです*。オブジェクト指向の世界でより種類の高い型を使用するには、この制限と一致する方法で型制約を表現する必要があります。

例えば、コメントで述べたように、我々は見ることができますOption<>し、List<>あなたが機能を持っている場合、あなたは変換することができることを意味において、「マッピング可能」とOption<T>Option<S>、またはList<T>List<S>。クラスを使用して上位の型を直接抽象化することはできないことを思い出して、代わりにインターフェイスを作成します。

IMappable<K<_>, T> where K<T> : IMappable<K<_>, T>

そして、インターフェイスを両方List<T>Option<T>as IMappable<List<_>, T>IMappable<Option<_>, T>それぞれ実装します。私たちがやったことは、より高い種類の型を使用して、実際の(より高い種類Option<T>でない)型とに制約を設定することですList<T>。これがScalaで行われている方法ですが、もちろんScalaには特徴、型変数、暗黙的なパラメーターなどの機能があり、表現力を高めています。

他の言語では、より高い種類の型を直接抽象化できます。型システムの最高権威の1つであるHaskellでは、より高い種類の型クラスであっても、任意の型の型クラスを表現できます。例えば、

class Mappable mp where
    map :: mp a -> mp b

これは、mp1つの型パラメーターを受け取る(指定されていない)型に直接配置される制約でありmap、をにmp<a>変換する関数に関連付ける必要がありますmp<b>。その後Mappable、オブジェクト指向言語で継承制約を設定できるように、より種類の高い型を制約する関数を作成できます。まあ、ちょっと。

まとめると、より高い種類の型を使用する能力は、それらを制約する能力、または型制約の一部として使用する能力に依存します。


仕事を変えるのに忙しすぎましたが、ついに自分の答えを書く時間を見つけるでしょう。ただし、制約の概念に気を取られていると思います。より高い種類の型の重要な側面の1つは、修飾するために論理的に表示できる任意の型に適用できる関数/動作を定義できることです。既存の型に制約を課すこととは異なり、型クラス(より親切な型の1つのアプリケーション)がそれらに動作を追加します。
-itsbruce

セマンティクスの問題だと思います。型クラスは、型のクラスを定義します。などの関数を定義するときに、型クラスのメンバーになるように(Mappable mp) => mp a -> mp b制約を設定しmpましたMappable。のOptionインスタンスなどの型を宣言すると、Mappableその型に動作が追加されます。型を制約することなく、その動作をローカルで使用できると思いますが、通常の関数を定義することと違いはありません。
グレッグロス

また、型クラスは、より高い種類の型に直接関連していないと確信しています。Scalaには、型クラスではなく、より種類の高い型があり、型クラスを、そのクラスを*使用不可にせずに、その型を持つ型に制限できます。ただし、より種類の高い型を操作する場合、型クラスが非常に強力であることは間違いありません。
グレッグロス

Scalaには型クラスがあります。それらは暗黙的に実装されます。暗黙は、Haskell型クラスインスタンスに相当するものを提供します。Haskellよりも脆弱な実装です。専用の構文がないためです。しかし、それは常にScala暗黙の重要な目的の1つであり、彼らは仕事をしています。
-itsbruce
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.