ML型推論の指数コストの簡潔な例


11

OCamlのような関数型言語での型推論のコストは非常に高くなる可能性があることに私の注意が向けられました。各式について、対応する型の長さが式の長さに対して指数関数的であるような一連の式があるという主張です。

以下のシーケンスを考案しました。私の質問は次のとおりです。同じ型を実現する、より簡潔な式のシーケンスを知っていますか?

# fun a -> a;;
- : 'a -> 'a = <fun>
# fun b a -> b a;;
- : ('a -> 'b) -> 'a -> 'b = <fun>
# fun c b a -> c b (b a);;
- : (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c = <fun>
# fun d c b a -> d c b (c b (b a));;
- : ((('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'c -> 'd) ->
   (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'd
= <fun>
# fun e d c b a -> e d c b (d c b (c b (b a)));;
- : (((('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'c -> 'd) ->
    (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'd -> 'e) ->
   ((('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'c -> 'd) ->
   (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'e
= <fun>
# fun f e d c b a -> f e d c b (e d c b (d c b (c b (b a))));;
- : ((((('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'c -> 'd) ->
     (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'd -> 'e) ->
    ((('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'c -> 'd) ->
    (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'e -> 'f) ->
   (((('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'c -> 'd) ->
    (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'd -> 'e) ->
   ((('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'c -> 'd) ->
   (('a -> 'b) -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'f
= <fun>

回答:


14

この回答では、言語のコアとなるMLフラグメントに固執しletます。Hindley-Milnerに続くラムダ計算とポリモーフィックのみです。完全なOCaml言語には、行のポリモーフィズム(正しく思い出せば理論上の複雑さは変わらないが、実際のプログラムでは型が大きくなる傾向がある)やモジュールシステム(十分に突っ込むと、 -抽象署名を含む病理学的なケースで終了する)。

コアMLプログラムに型があるかどうかを判断するための最悪の場合の時間の複雑さは、プログラムのサイズの単純な指数関数です。この結果の古典的な参照は[KTU90]と[M90]です。[S95]では、より基本的ではあるが不完全な扱いが与えられています。

コアMLプログラムのタイプのタイプの最大サイズは、実際にはプログラムのサイズの倍の指数関数です。型チェッカーがプログラムの型を出力する必要がある場合、時間は二重に指数関数になる可能性があります。ツリーの繰り返し部分の省略形を定義することにより、単純な指数に戻すことができます。これは、実装で型ツリーの一部を共有することに対応できます。

あなたの例は、型の指数関数的増加を示しています。ただし、型の繰り返される部分に省略形を使用することにより、型の線形サイズ表現を指定できることに注意してください。これは、実装で型ツリーの一部を共有することに対応できます。例えば:

# fun d c b a -> d c b (c b (b a));;
t2 -> t2
where t2 = (t1 -> 'b -> 'c) -> t1 -> 'a -> 'd
where t1 = 'a -> 'b

(x,x)xpairNΘ2N

# let pair x f = f x x;;
# let pairN x = pair (pair (pair … (pair x)…));;
'a -> tN
where tN = (tN-1 -> tN-1 -> 'bN) -> 'bN
…
where t2 = (t1 -> t1 -> 'b2) -> 'b2
where t1 = ('a -> 'a -> 'b1) -> 'b1

ネストされたポリモーフィックを導入することにより let定義を、型のサイズが再び指数関数的に増加します。今回は、どの程度の共有でも指数関数的成長を打ち消すことはできません。

# let pair x f = f x x;;
# let f1 x = pair x in
  let f2 x = f1 (f1 x) in
  let f3 x = f2 (f2 x) in
  fun z -> f3 (fun x -> x) z;;

参考文献

[KTU90] Kfoury、J。ティウリン; Urzyczyn、P.(1990)。「ML typabilityはdexptime-complete」です。コンピュータサイエンスの講義ノート。CAAP '90 431:206-220。[ スプリンガー ] [ グーグル ]

[M90]メイソン、ハリーG(1990)。「MLのタイプ可能性の決定は、決定論的な指数時間で完了します」。第17回プログラミング言語の原則に関するACM SIGPLAN-SIGACTシンポジウムの議事録。POPL '90(ACM):382–401。[ ACM ]

[P04]ベンジャミンC.ピアス。タイプとプログラミング言語の高度なトピック。MIT Press、2004年。[ Amazon ]

[PR04]フランソワ・ポティエとディディエ・レミー。「ML型推論の本質」。[P04]の第10章。[ pdf ]

[S95]マイケル・I・シュワルツバッハ。ポリモーフィック型推論。BRICSのLS-95-3、1995年6月PS


だから基本的に、型推論と結合した型式の「構成的」性質が問題の根源ですか?
ディディエルク2013

1
@didiercコメントが理解できません。多くのものは構成的です。ある意味で、基本的な理由は、オブジェクトの複製(2つの型が同じであるという制約)とペアリング(->演算子)の基本操作から、指数関数的成長(フィボナッチツリー)を行えることです。
Gilles 'SO-悪をやめる'

ええ、私はそれが私が意味したことだと思います:型代数は定義的に構成的です(あなたは答えで「ペア関数を構成する」という用語を使用しました、それはおそらく私が単語を選んだ場所です)、ある意味でthaf型式は式と演算子が小さくなり、式の新しい構成ごとに式のサイズが少なくとも係数2でスケーリングされます(より複雑なポリモーフィック型では、3つ以上の場合、係数は大きくなります)。
didierc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.