適用順言語は、一定時間の配列書き込みをサポートしていませんか?そうでない場合、なぜそうではないのですか?


7

私はSteven Skienaの「The Algorithm Design Manual」を読んでおり、155ページの彼のウォーストーリーの 1つで彼は次のように述べています。

Mathematicaでは、計算の適用モデル(配列への一定時間の書き込み操作をサポートしていない)と解釈のオーバーヘッド(コンパイルではない)のため、効率はMathematicaの大きな課題です。

私はすでにSICPを読んでいるので、適用言語と通常順序言語の違いに精通しています(つまり、通常順序言語は必要になるまで手続き引数の評価を遅らせますが、適用順序言語はそれらが評価されるとすぐに評価しますプロシージャが呼び出されます)。しかし、上記のスキーナの文は、アプリケーション順言語のアイデアと、一定時間より悪い配列書き込みのアイデアとを関連付けているようです。AbelsonとSussmanが彼らのテキストでこれを言及したのを覚えていないので、これは驚きでした。

trueの場合、アプリケーション順言語が一定の時間内に配列に書き込みを行わない理由は何ですか?配列の書き込み時間を決定するときに評価の順序が重要になるのはなぜですか?

私はビッグ-Oの書き込みパフォーマンスは何も興味がある決定的な答えがありますしない限り、私はその質問をスキップしますので、この場合には、私は言語の実装に依存している想像してみてください。

回答:


11

スキエナは「適用」とは言わず、「適用」とだけ言った。これは、「純粋に機能的な」、または状態操作コマンドの実行とは対照的に関数の適用を介して評価する言語などの意味として使用されることがあります。Mathematica(少なくとも現在では)は純粋に機能的ではありませんが、純粋に機能的なプログラミングスタイルを強く奨励しているようです。

Haskellなどの純粋に関数型の言語では、数学と同様に、関数を値に適用して新しい値を生成します。数学のように、そのような言語では、変数は単なる値の名前です。「を」と言うと、とはどこでも交換可能です。をに設定すると言うよりも、をに「変更」することについて話すのは意味がありません。配列の場合、これは配列を「更新」するには、変更を加えた新しい配列を作成することを意味します。明らかに、変更する1つのエントリを除いて、配列のコピー全体を構築するのはコストがかかります。これはほぼ間違いなく、スキーナが言及している問題です。バツ1バツ1バツ212

私の知る限り、これに対する完全に満足のいく答えはありません。つまり、一定時間の検索とすべてのバージョンの更新提供する純粋に機能的なデータ構造はありません。あなたは作ることができます(外部)の純粋なデータ構造のため、一定時間の検索や更新を提供し、最新のバージョン、ただしアレイの古いバージョンへのアクセスは遅くなります。モナドまたは一意性タイプを使用して、コンパイラーがインプレース更新を使用できるようにする配列の使用を強制できますが、これは命令型のアプローチを使用することと同じです(ただし、制御された方法で抑制されます)。実際には、純粋な関数型言語のプログラマーは、命令型プログラマーと同じくらい配列を使用しないだけでなく、配列を使用する場合、一括操作を使用する傾向があります。とにかく配列のすべての要素を操作する場合、配列をコピーするコストは要素ごとに一定です。

純粋に関数型プログラミングの制限により効率的な実装が自明にならない場合は確かにありますが、ほとんどの場合、命令型言語での典型的/実用的なものとは異なる設計および実装手法を適用するだけの問題です。純度はまた、多くの設計、最適化、そして時には全体の技術を実用的にする保証を提供します。まず、最も純粋に機能的なデータ構造は、可能な限り共有するように設計されています。第二に、バルク操作のパフォーマンスを向上させるための主要な手法は、複数のバルク操作を1つに結合して中間を回避するフュージョンです。最後に、


3
また、ファンアウトの大きいツリーデータ構造は「実質的に一定」です。たとえば、40億の要素を持つ64進ツリーは、ルートからリーフまで最大7ホップです。これは、配列の1つではなく7つのポインタールックアップです。悪くない。Clojureの設計者であるRich Hickeyは、ClojureのベクトルはO(log_32 n)であり、多くの実際的な問題のサイズでは定数が重要であるため、32が重要であると言っています。X> 30のO(log_X n)は、n〜10億と非常に大きくても、O(1)にかなり近いです。
イェルクWミッターク

4
@JörgWMittagハードウェアがメモリセルにアクセスするためにO(log n)ゲートを通過する必要があるため、命令型の世界でさえ、O(1)配列アクセスは小さな嘘です。RAMコストモデルはO(1)アクセスを都合よく仮定しています。それは、練習するのに十分近いためです(とにかく、何十億バイトものメモリがない場合)。
カイ

@JörgWMittag:おそらく私は誤解しているかもしれませんが、あなたが説明するような純粋に機能的なツリー構造では、取得は7倍のコストになりますが、更新は7x64倍のコストになり、すべての新しい割り当てコストを割り引いても配列。読み取りと書き込みの比率が非常に高い場合を除いて、それは簡単なトレードオフではありません。
ruakh
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.