上位のパラメトリック多型は有用ですか?


16

私は誰もがフォームの一般的なメソッドに精通していると確信しています:

T DoSomething<T>(T item)

この関数は、パラメータポリモーフィック(PP)、特にランク1 PP とも呼ばれます。

このメソッドは、次の形式の関数オブジェクトを使用して表現できるとしましょう。

<T> : T -> T

つまり、<T>1つの型パラメーターを受け取り、1つの型のパラメーターをT -> T受け取りT、同じ型の値を返すことを意味します。

その場合、次はランク2 PP関数になります。

(<T> : T -> T) -> int 

この関数は、型パラメーター自体を受け取りませんが、型パラメーターを受け取る関数を受け取ります。これを繰り返し続けて、ネストをより深くし、より高いランクのPPを取得できます。

この機能は、プログラミング言語では非常にまれです。Haskellでさえ、デフォルトでは許可していません。

便利ですか?他の方法では説明が難しい動作を説明できますか?

また、何かが命令的であるとはどういう意味ですか?(このコンテキストで)


1
興味深いことに、TypeScriptは、ランクn PPを完全にサポートする1​​つの主流言語です。たとえば、次は有効なTypeScriptコードですlet sdff = (g : (f : <T> (e : T) => void) => void) => {}
。– GregRos

回答:


11

一般に、呼び出し先ではなく、呼び出し元ではなく型パラメーターの値を選択できるようにする場合は、上位のポリモーフィズムを使用します。例えば:

f :: (forall a. Show a => a -> Int) -> (Int, Int)
f g = (g "one", g 2)

任意の機能g私は、これに合格していることは、f私に与えることができなければならないIntいくつかの型の値からだけの事はg、そのタイプを知っている、それはのインスタンスを持っていることですShow。これらはコーシャです:

f (length . show)
f (const 42)

しかし、これらはそうではありません:

f length
f succ

1つの特に有用なアプリケーションは、のスコープを強制するためにのスコープを使用することです。typeのオブジェクトがあり、futureやコールバックなどAction<T>、typeの結果を生成するために実行できるアクションを表すとしTます。

T runAction<T>(Action<T>)

runAction :: forall a. Action a -> a

ここで、オブジェクトActionを割り当てることができるを持っているとしResource<T>ます:

Action<Resource<T>> newResource<T>(T)

newResource :: forall a. a -> Action (Resource a)

これらのリソースは、それらが作成された場所内でのみ使用Actionされ、異なるアクション間または同じアクションの異なる実行間で共有されないように強制します。

上位の型を使用Sして、Resourceand Action型にパラメーターを追加することでこれを達成できます。これは完全に抽象的です。これはの「スコープ」を表しActionます。署名は次のとおりです。

T run<T>(<S> Action<S, T>)
Action<S, Resource<S, T>> newResource<T>(T)

runAction :: forall a. (forall s. Action s a) -> a
newResource :: forall s a. a -> Action s (Resource s a)

私たちが与えたときに今、私たちは、「スコープ」のパラメータがあるためと確信している、完全に多型である、それはの本体を免れることはできない-SO使用するタイプのいずれかの値などが同様に逃げることができませんの!runActionAction<S, T>SrunActionSResource<S, int>

(Haskellでは、これはSTモナドとして知られており、どこrunActionで呼ばれrunSTResource呼ばれSTRef、そしてnewResource呼ばれnewSTRefます。)


STモナドは非常に興味深い例です。上位の多型がいつ役立つかについて、いくつか例を挙げていただけますか?
グレッグロス

@GregRos:実存にも便利です。Haxl、我々は、実存のようであったdata Fetch d = forall a. Fetch (d a) (MVar a)データ・ソースへの要求の組であり、dその結果を格納するためのスロット。結果とスロットは一致するタイプを持っている必要がありますが、そのタイプは非表示であるため、同じデータソースへの異種のリクエストのリストを作成できます。上位のポリモーフィズムを使用して、1つのリクエストを取得する関数を指定すると、すべてのリクエストを取得する関数を作成できますfetch :: (forall a. d a -> IO a) -> [Fetch d] -> IO ()
ジョンパーディ

8

上位のポリモーフィズムは非常に便利です。System F(おなじみの型付きFP言語のコア言語)では、これは実際にSystem Fがプログラミングを行う方法である「型付き教会エンコード」を許可するために不可欠です。これらがなければ、システムFはまったく役に立ちません。

システムFでは、数値を次のように定義します

Nat = forall c. (c -> c) -> c -> c

加算にはタイプがあります

plus : Nat -> Nat -> Nat
plus l r = Λ t. λ (s : t -> t). λ (z : t). l s (r s z)

これは上位の種類です(forall c.これらの矢印の内側に表示されます)。

これは他の場所でも発生します。たとえば、計算が適切な継続渡しスタイル(google "codensity haskell")であることを示したい場合は、次のようにします。

type CPSed A = forall c. (A -> c) -> c

System Fの無人型について話す場合でも、より高いランクの多型が必要です

type Void = forall a. a 

これの長短は、純粋な型システム(System F、CoC)で関数を記述するために、興味深いデータを処理する場合、より高いランクの多態性を必要とします。

特にSystem Fでは、これらのエンコーディングは「不可解」である必要があります。これは、forall a.絶対的にすべてのタイプを定量化することを意味します。これには、私たちが定義しているタイプそのものが決定的に含まれています。その中forall a. aa実際にforall a. a再び立つことができます!MLのような言語では、これは当てはまりません。型変数は、量指定子(モノタイプと呼ばれる)を持たない型のセットに対してのみ定量化するため、「予測的」であると言われています。in plusをインスタンス化したため、必要な不可逆性の定義も!cl : NatNat

最後に、任意の再帰型を持つ言語(System Fとは異なります)でも、不可逆性と上位のポリモーフィズムの両方を必要とする最後の理由に言及したいと思います。Haskellには、「状態スレッドモナド」と呼ばれるエフェクト用のモナドがあります。アイデアは、状態スレッドモナドはあなたが物事を変化させることができるが、結果が変更可能なものに依存しないようにそれをエスケープする必要があるということです。これは、ST計算が明らかに純粋であることを意味します。この要件を実施するために、上位のポリモーフィズムを使用します

runST :: forall a. (forall s. ST s a) -> a

ここで、それaが導入する範囲の外にバインドされることを保証することでs、私たちはそれaが依存しない整形式のタイプを表すことを知っていますssその特定の状態スレッド内のすべての変更可能なものをパラメトリック化するために使用するためa、変更可能なものから独立しているため、そのST計算の範囲を逃れるものはありません。型を使用して不正なプログラムを除外する素晴らしい例です。

ところで、もしあなたが型理論について学ぶことに興味があるなら、私は良い本または2冊に投資することをお勧めします。このことを少しずつ学ぶことは困難です。PL理論全般(および型理論のいくつかの要素)に関するPierceまたはHarperの本の1つをお勧めします。「型とプログラミング言語の高度なトピック」という本には、大量の型理論も含まれています。最後に、「Martin Lofの型理論におけるプログラミング」は、Martin Lofが概説した内包型型理論への非常に良い説明です。


ご提案ありがとうございます。それらを調べます。このトピックは本当に興味深いものであり、より高度な型システムの概念がより多くのプログラミング言語に採用されることを望んでいます。彼らはあなたにはるかに表現力を与えます。
グレッグロス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.