ポリモーフィックリストからポリモーフィックリストへのML関数


8

私はML(OCaml)でプログラミングを学んでいます。以前に、タイプのML関数'a -> 'bについて質問しました。今、私はタイプの関数で少し実験しています'a list -> 'b list。明らかな簡単な例がいくつかあります。

let rec loop l = loop l
let return_empty l = []
let rec loop_if_not_empty = function [] -> []
                                   | l -> loop_if_not_empty l

(ライブラリ関数を使用せずに)空のリストまたはループを返す以外のことを行う関数を作成する方法がわかりません。これはできますか?空でないリストを返す方法はありますか?

編集:はい、私がtypeの関数を持っている場合は、'a -> 'b別の関数またはtypeの関数を作成できますが'a list -> 'b list、ここで私が疑問に思っているのは、最初の関数を作成する方法です。


1
前の質問と同様に、回答でCS101学生学習プログラミングをターゲットにしてください。回答が彼を後押しする可能性があるタイプ理論家ではありません。
Gilles「SO-邪悪なことをやめよう」

空でないリストを返すこのタイプの関数fがある場合、fun a-> List.hd(f [a])は、終了せずに例外を発生させることなく、タイプ 'a->' bを持つことに注意してください。
ガレーヌ2012年

回答:


6

まあ、パラメトリック性として知られているものは、MLの純粋なサブセット(つまり、無限再帰、refおよびすべての奇妙なもの)を考えると、空を返すもの以外にこのタイプの関数を定義する方法がないことを示していますリスト。

これはすべて、Wadlerの論文「Theorems for free!」から始まりました」。このペーパーは、基本的に、2つのことを教えてくれます。

  1. 特定の条件を満たすプログラミング言語を検討する場合、多態性関数の型シグネチャ(これはパラメトリック性定理と呼ばれます)を調べるだけで、いくつかのクールな定理を推測できます。
  2. ML(無限再帰なし、refおよびすべての奇妙なもの)は、これらの条件を満たす。

Parametricity定理から、我々は我々が機能を持っている場合ことを知ってf : 'a list -> 'b list、そしてすべてのために'a'b'c'dおよびすべての機能のためにg : 'a -> 'ch : 'b -> 'd私たちは持っています:

map h ∘ f = f ∘ map g

(注意:f左側にはタイプが'a list -> 'b listありf、右側にはがあり'c list -> 'd listます。)

私たちはg好きなものを自由に選択できるので、'a = 'cとさせてくださいg = id。今以来map id = id(簡単の定義に関する帰納法により証明するためにmap)、我々は持っています:

map h ∘ f = f

さあ、'b = 'd = boolそしてh = not。ある人のためにzs : bool listそれが起こると仮定しましょうf zs ≠ [] : bool list。成立map not ∘ f = fないことは明らかです、なぜなら

(map not ∘ f) zs ≠ f zs

右側のリストの最初の要素がである場合、true左側の最初の要素はでfalseあり、その逆も同様です。

これは、私たちの仮定が間違っていることを意味しますf zs = []。終わりましたか?番号。

私たちは、その仮定'bですbool。私たちは時にあることを示してきたfタイプで呼び出されたf : 'a list -> bool listいずれかのために'af常に空のリストを返す必要があります。それが別のものを返すfので、f : 'a list -> unit listそれを呼び出すとそれはそれであることができますか?私たちの直感はこれがナンセンスだと教えてくれます:ブール値のリストを提供したいときに常に空のリストを返し、そうでなければ空でないリストを返す可能性のある関数を純粋なMLで書くことはできません!しかし、これは証拠ではありません。

私たちが言いたいことはつまり、fある均一な:それは常にのために空のリストを返す場合bool list、それはしなければならないため、空のリストを返すunit listと、一般的には、任意の'a list。これが、私の回答の冒頭にある箇条書きの2番目のポイントについての説明です。

この論文は、MLでは関連する値を関連する値にするf必要があることを示してます。私は関係の詳細につもりはない、リストがされていると言うのに十分です関連であれば、彼らは同じ長さを有し、その要素が対に関連している場合にのみ(である、としている場合にのみ場合は関連しているとに関連していますなどに関連しています)。そして、楽しい部分があるため、我々の場合には、ある多型である、我々が定義することができる任意のリストの要素の関係を![x_1, x_2, ..., x_m][y_1, y_2, ..., y_n]m = nx_1y_1x_2y_2f

のは、いずれかを選択してみましょう'a'bと見てf : 'a list -> 'b list。今見てくださいf : 'a list -> bool list。この場合はf常に空のリストを返すことはすでに示しました。ここで、のすべての要素が'a自分自身に関連していると仮定します(必要な任意の関係を選択できることを忘れないでください)。これzs : 'a listは、いずれかが自分自身に関連していることを意味します。ご存じのように、fは関連する値を関連する値に取ります。これf zs : 'b listはに関連していることを意味しますf zs : bool listが、2番目のリストの長さはゼロに等しく、最初のリストはそれに関連しているため、空です。


完全を期すために、Wadlerの元の論文には、一般的な再帰の影響に関するセクション(終了しない可能性がある)があり、の存在下での自由定理を探究している論文もありseqます。


今、私は証拠ではなく、機能によって誘発される特定の関係を考慮してparametricity定理を弱める(場合は、1つのステップで行うことができます疑いがあるghカスタムメイドの一般的な関係...とまっすぐ行くこの場合)
kirelagin

ちなみに、パラメトリック性は、(パラメトリック性を定義するためのアプローチの要約であると主張する)ワドラーの論文から始まりません。このアイデアは、レイノルドの論文「タイプ、抽象化、パラメトリック多態性」にさかのぼります。この考えは、私が知る限り、システムFの正規化の証拠にもある程度存在していました。
Daniel Gratzer、2015年

4

簡単なオブジェクトに戻りましょう。タイプの適切なオブジェクトを構築することはできません。'aそれは、このオブジェクトxが適切な場所で使用できることを意味'aするためです。そして、それはあらゆる場所を意味します:整数、配列、さらには関数として。たとえば、これはx+2x.(1)や、などのことができることを意味します (x 5)。これを防ぐために型が正確に存在します。

これはtypeの関数に適用されるのと同じ考えです'a -> 'bが、この型が存在する場合があります。関数が決して typeのオブジェクトを返さない'b場合:ループまたは例外を発生させる場合。

これは、リストを返す関数にも当てはまります。関数がタイプでt -> 'b listあり、タイプのオブジェクトを作成tしてこの関数に適用する場合、このリストの要素に正常にアクセスすると、すべてのタイプのオブジェクトにアクセスすることになります。そのため、リストのどの要素にもアクセスできません。リストが空であるか、...リストがありません。

ただし、タイプ'a list -> 'b listは通常の演習で表示されますが、それはタイプの関数がすでにある場合に限られます'a -> 'b

let rec map (f : 'a -> 'b) =
  function
  | [] -> []
  | x :: xs -> f x :: map f xs

しかし、あなたはおそらくこれを知っています。

val map : ('a -> 'b) -> 'a list -> 'b list

1
古いタイプの理論家は、この回答に感動するほどではありません。空ではない型変数コンテキストは、文字通り型'a -> 'bまたはの関数を持つ方法ですが'a list -> 'b list、それはそれほど興味深い観察ではありません。実際、質問を編集して、これがプログラミングを学ぶ若い学生が疑問に思っていたものではないことを明確にするつもりです。
Gilles「SO-邪悪なことをやめなさい」

しかし、古いタイプの理論家は、MLに論理的な欠陥がないことを知っています。あなたは、関数を生成することができた場合f : 'a list -> 'b listtなるようにf t <> []、このプログラムはチェックを入力しますが、行うことができます方法例外を発生させるよりも悪いです:let y = List.hd (f t) in (y y) (y + y.(0) + y.(0).(0))
jmad

2

Parametricity定理から「Freeの定理!」紙は、ML用語には非常に特殊な特性があることを示しています。用語のタイプをこのタイプの値の関係として見る場合、この用語の値はそれ自体に関連しています。タイプを関係として表示する方法は次のとおりです。

  • 関数タイプ'a -> 'bは、2つの関数が関連する値に関連する値を取る場合に関連すると言うことによって定義された関係に対応します(一部の関係にあると想定し'a'b対応します)。
  • リストタイプ'a listは、2つのリストが同じ長さであり、一致する要素が関連している場合に2つのリストが関連していると言うことによって定義された関係に対応します('aある関係に対応していると想定)。
  • (今、最も興味深い部分。)私たちが選択することができた場合に2つの多型の値が関連していると言って定義された関係へのポリモーフィック型に相当する任意の二つのタイプ、任意の、これらのタイプの要素間の関係をこのように型変数のすべてのインスタンスを置き換えますリレーション、および結果の値はまだ関連しています。

ここに例があります。用語があるとしましょうfoo : 'a -> 'a。パラメトリック性定理はそれfooはそれ自体に関連していると言います。つまり、2つのタイプを選択できるということです。1 そして 2、絶対に任意の関係を選択する このタイプの要素間、および a11 そして a22、それらは次のように関連しています 、その後 fooa1 そして fooa2 に従っても関連付けられます

a1a2fooa1fooa2

今私たちが関係を取るなら 任意の関係ではなく、関数 f12、上記は次のようになります。

fa1=a2ffooa1=fooa2

または、言い換えると:

ffooa1=foofa1

これは、id関数の自由定理ですf . id = id . f


関数に対して同様の手順を実行するとfoo : 'a list -> 'b list、任意の2つのタイプを選択できることがわかります1 そして 2、任意の関係 要素間、任意の2つのタイプ B1 そして B2、任意の関係 B それらの要素の間で、次に最初にの要素で作られた任意の2つのリストを取ります 1、2番目の要素で構成される 2、関数を両方のリストに適用します(リストのリストを取得します) B1 最初のケースとのリスト B2 2番目)、および入力が関連していた場合、結果も関連します。

今、私たちは、任意の2つのタイプのためにそれを証明するためにこれを使用Aし、B機能はfoo、任意の入力のための空のリストを返しますas : A list

  • しましょう 1=2= A そしてましょう アイデンティティ関係であるため、 自明です。
  • しましょう B1= ØB2= B そして B それらの間の任意の関係(空の関係は1つしかありませんが、それは問題ではありません)。
  • asはそれ自体に関連している(私たちはでの同一関係を選択したAため)、したがってfoo as : Ø listに関連していfoo as : B listます。
  • 2つのリストは、長さが等しい場合にのみ関連付けられることがわかっていますØ。また、型の要素がないため、結果の最初のリストは空でなければならないこともわかっています。

したがって、いずれかのためにABそしてas : A list私たちは、それが持っているfoo as : B list空のリストである必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.