1. ホーム
  2. スカラ

[解決済み】ScalaのHigher kinded typeとは何ですか?

2022-03-30 08:36:08

質問

をWeb上で確認することができます。

  1. 上位 kinded type == type constructor?

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

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

    <ブロッククオート

    上位互換型 は、他の型を受け取って新しい型を構築する型です。

    これらは タイプコンストラクタ . (例えば Scalaでプログラミング ).

  2. 上位互換型 == 型パラメータとして型コンストラクタを受け取る型コンストラクタ?

    論文では より高い種類のジェネリックス を読むことができます。

    <ブロッククオート

    ... 型の上に抽象化された型があり、その型の上に抽象化された型がある。 ('higher-kinded types') ..."

    ということを示唆しています。

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

    は、より上位の種類を持つ型です。

ということを考えると、区別がつきにくいですね。 タイプコンストラクタ , 上位互換型 そして 型パラメータとして型コンストラクタを受け取る型コンストラクタ。 ということで、上の質問です。

どのように解決するのですか?

この混乱を補うために、曖昧さ回避の方法を説明します。 私は、人々がより慣れ親しむことができるように、価値レベルに例えて説明するのが好きです。

<ブロッククオート

型コンストラクタは、型引数に適用して型を "construct"することができる型です。

値コンストラクタは、value 引数に適用して値を構築するものです。

値のコンストラクタは通常、quot;function" またはquot;method" と呼ばれます。これらのコンストラクタは、(さまざまな形状のものを構築するために使用できるため)「多相性」、または「抽象化」(異なる多相性のインスタンス間で変化するものを抽象化するため)とも呼ばれます。

抽象化/ポリモーフィズムの文脈では、一次とは抽象化の「一回限りの使用」のことである。Java 5のジェネリックスは一次関数です。

上記の抽象化の特徴付けを一次的に解釈すると、以下のようになる。

型構成子とは、適切な型の引数に適用して、"construct"適切な型を構成することができる型のことです。

値コンストラクタは、適切な値の引数に適用して、適切な値を構築します。

抽象化されていないことを強調するために(これを "ゼロ次" と呼ぶことができると思いますが、私はこれが使われているところを見たことがありません)、例えば、値 1 または型 String 通常、私たちは何かを「適切な値」または「適切な型」と呼びます。

適切な値とは、引数を待たない(引数を抽象化しない)という意味で、"すぐに使える"です。簡単に印刷や検査ができる値だと考えてください(関数を直列化するのはズルです!)。

適切な型とは、値を分類する型(値コンストラクタを含む)であり、型コンストラクタはいかなる値も分類しません(適切な型を得るためには、まず正しい型引数に適用される必要があります)。型をインスタンス化するには、その型が適切な型であることが必要です(十分ではありませんが)。(抽象クラスやアクセスできないクラスかもしれません)。

高次とは、単にポリモーフィズムと抽象化の繰り返しを意味する総称である。ポリモーフィズムの型や値も同じ意味です。具体的には、高次の抽象化は、何かを抽象化したものをさらに抽象化する。型については、より一般的な "higher-order" の特殊用途版として "higher-kinded" という用語がある。

したがって、我々の特徴づけの高次バージョンは次のようになる。

<ブロッククオート

型引数(適正型や型構成子)に適用して、適正型(構成子)を "construct"することができるのが、型構成子です。

値コンストラクタは、value 引数(適切な値または値コンストラクタ)に適用して、適切な値(コンストラクタ)を構築するための値です。

したがって、quot;高次"とは、単に、quot;X"を抽象化すると言うとき、本当にそれを意味しているのだ! ということです。 X 抽象化されても、抽象化される権利は失われないので、好きなだけ抽象化できる。(ちなみに、ここでは「値や型の定義に必須でないものを省き、抽象化の使用者が引数として変化させたり提供したりできるようにする」という意味で動詞"abstract"を使っています)

以下は、(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 では直接表現できませんが,構造型を使えば構文のオーバーヘッドをあまり気にせずに済みます ( -スタイルによるものです。 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

(個人的なことですが、今まで「高次の型」(quot; higher-kinded types")について話してきたことを後悔しています、結局はただの型なんですから! 曖昧さをなくす必要がある場合は、quot;タイプコンストラクタパラメータ、quot;タイプコンストラクタメンバー、quot;タイプコンストラクタエイリアス、などと言うと、単なる型の話ではないことが強調できます)。

ps: さらに問題を複雑にするのは、"polymorphic" が別の意味で曖昧なことです。なぜなら多相型は時に、次のような普遍的に数量化された型を意味するからです。 Forall T, T => T これは多相な値を分類するため、適切な型である(Scala では、この値は構造型である {def apply[T](x: T): T = x} )