web-dev-qa-db-ja.com

純粋に機能的なプログラミングの効率

命令的ではなく純粋に機能的にプログラミングする場合に発生する可能性のある最悪の漸近的スローダウン(つまり、副作用を許可する)を誰もが知っていますか?

itowlsonによるコメントからの明確化:最もよく知られている非破壊アルゴリズムが、最も知られている破壊アルゴリズムよりも漸近的に悪化する問題はありますか?

395
Opt

Pippenger [1996] によれば、純粋に機能する(遅延ではなく厳密な評価セマンティクスを持つ)LISPシステムをデータを変更できるシステムと比較する場合、O(n)は、O(nlogn)時間で実行される純粋なLISPのアルゴリズムに変換できます( Ben-AmramおよびGalil [1992] ポインターのみを使用したランダムアクセスメモリのシミュレーションについて)。Pippengerは、それができる最善のアルゴリズムがあることも確立しています; O(n)の問題があります純粋なシステムではΩ(nlogn)である不純なシステム。

この論文についていくつか注意点があります。最も重要なのは、Haskellなどの遅延関数型言語に対応していないことです。 Bird、Jones and De Moor [1997] Pippengerによって構築された問題はO(n)時間で怠laな関数型言語で解決できることを実証するが、確立していない(そして、私が知っているように、怠zyな関数型言語が突然変異のある言語と同じ漸近的な実行時間ですべての問題を解決できるかどうかは誰も知らない。

Pippengerによって構築された問題はΩ(nlogn)を必要とするため、この結果を達成するために特別に構築されており、実際の現実の問題を必ずしも表すものではありません。問題にはいくつかの制限がありますが、少し予想外ですが、証明が機能するために必要です。特に、この問題では、将来の入力にアクセスできずに結果がオンラインで計算されること、および入力が固定サイズセットではなく、無制限の可能な原子セットからの原子のシーケンスで構成されることが必要です。また、この論文では、線形実行時間の不純なアルゴリズムの結果(下限)のみを確立しています。より長い実行時間を必要とする問題の場合、線形問題に見られる余分なO(logn)要因は、アルゴリズムに必要な追加の操作の過程で「吸収」される可能性があります実行時間が長くなります。これらの説明と未解決の質問は、 Ben-Amram [1996]

実際には、可変データ構造を持つ言語と同じ効率で、多くのアルゴリズムを純粋な関数型言語で実装できます。純粋に機能的なデータ構造を効率的に実装するために使用する手法の良いリファレンスについては、 Chris Okasaki's "Purely Functional Data Structures" [Okasaki 1998] (これは彼の論文の拡張版です [Okasaki 1996] )。

純粋に機能的なデータ構造にアルゴリズムを実装する必要がある人は誰でも岡崎を読んでください。バランスの取れたバイナリツリーを使用して可変メモリをシミュレートすることにより、操作ごとに常に最悪の場合O(logn)のスローダウンを得ることができますが、多くの場合、それよりもはるかに良いことができます。償却された手法から、償却された作業を段階的に行うリアルタイム手法まで。純粋に機能的なデータ構造は、操作や分析が少し難しい場合がありますが、コンパイラーの最適化、並列分散コンピューティング、バージョン管理、取り消し、ロールバックなどの機能の実装に役立つ参照透過性など、多くの利点があります。

また、これはすべて漸近的な実行時間のみを説明していることに注意してください。純粋に機能的なデータ構造を実装するための多くの手法は、それらが機能するために必要な余分なブックキーピングと問題の言語の実装の詳細のため、一定量の一定の要因の減速をもたらします。純粋に機能的なデータ構造の利点は、これらの一定の要因による速度低下を上回る場合があるため、通常、問題の問題に基づいてトレードオフを行う必要があります。

参照資料

527
Brian Campbell

実際には、怠efficientであっても漸近的に効率的な純粋に機能的なソリューション(純粋なラムダ計算で実装可能なもの)が知られていないいくつかのアルゴリズムとデータ構造があります。

  • 前述の組合発見
  • ハッシュテーブル
  • 配列
  • いくつかのグラフアルゴリズム
  • ...

ただし、「命令型」言語では、メモリへのアクセスはO(1)であると仮定します。常にO(log n)。関数型言語でエミュレートできます。

また、実際にすべての現代の関数型言語は可変データを提供し、Haskellは純度を犠牲にすることなくそれを提供することも覚えておく必要があります(STモナド)。

44
jkff

この記事nion-findアルゴリズム の既知の純粋に機能的な実装はすべて、純粋に機能的なインターフェースを備えているが変更可能なデータを使用するパブリッシュするものよりも漸近的複雑さが劣ると主張しています内部的に。

他の回答が違いは決してないと主張し、たとえば、純粋に機能的なコードの唯一の「欠点」は、並列化できるということであり、これらの問題に関する機能プログラミングコミュニティの情報/客観性のアイデアを提供します。

編集:

以下のコメントは、純粋な関数型プログラミングの長所と短所に関する偏った議論は、「関数型プログラミングコミュニティ」から来るものではない可能性があることを指摘しています。いい視点ね。おそらく、私が見ている支持者は、コメントを引用すれば、「文盲」であるに過ぎません。

たとえば、この ブログ投稿 は、関数型プログラミングコミュニティの代表と言える人物によって書かれたもので、「遅延評価のポイント」のリストなので、怠zyで純粋に機能的なプログラミングが持つかもしれない欠点について言及する良い場所です。良い場所は、次の(技術的には正しいが、面白くないという点に偏っている)解雇の代わりになるでしょう。

Strict関数でstrictがO(f(n))複雑さを持つ場合、遅延言語でもO(f(n))複雑さを持ちます。なぜ心配なの? :)

35
Pascal Cuoq

メモリ使用量の上限が固定されているため、違いはありません。

証明スケッチ:メモリ使用量の上限が固定されている場合、実際にそのマシンで実行しているのと同じ漸近的な複雑さで命令型命令セットを実行する仮想マシンを作成できるはずです。これは、可変メモリを永続データ構造として管理し、O(log(n))読み取りおよび書き込みを行うことができるためですが、メモリ使用量の上限が固定されているため、固定量を使用できるためです。これらをO(1)に減衰させます。したがって、機能実装はVMの機能実装で実行される必須バージョンである可能性があるため、両者は同じ漸近的な複雑さを持つ必要があります。

4
Brian

Haskellのパフォーマンス を読んでから、 ベンチマークゲーム 関数型言語と手続き型/ OO言語のパフォーマンスを確認することをお勧めします。

1