2

そうではないと思います。

私の理由は、Haskell は純粋な関数型プログラミング (I/O モナドなし) であり、「名前」が同じであれば、すべての「名前による呼び出し」で同じ評価値を使用することができたからです。

実装の詳細については何も知りませんが、非常に興味があります。
詳細な説明は大歓迎です:)

ところで、私はグーグルを試しましたが、役に立つものを手に入れるのはかなり困難でした.

4

2 に答える 2

9

まず第一に、Haskell は実装ではなく仕様です。このレポートでは、名前による呼び出し評価や遅延評価を実際に使用する必要はありません。Haskell の実装は非正格であることが要求されるだけであり、値による呼び出しや同様の戦略は除外されます。

したがって、厳密に言えば (ha, ha)、評価戦略によって Haskell が遅くなることはありません。何Haskell の速度を低下させているのかはわかりませんが、Haskell 98 の後にレポートの次のバージョンを出すのに 12 年もかからなかったことは明らかですが、どうにかして委員会が関与しているのではないでしょうか。


とにかく、「遅延評価」は「必要に応じて呼び出す」戦略を指し、これは Haskell の最も一般的な実装の選択肢です。これは、部分式が複数の場所で使用されている場合、最大で 1 回評価されるという点で、名前による呼び出しとは異なります。

共有される部分式と見なされるものの詳細は少し微妙で、おそらく多少実装に依存しますが、GHC Haskell の例を使用するcycleには、入力リストを無限に繰り返す function を考えてください。単純な実装は次のようになります。

cycle xs = xs ++ cycle xs

共有できる単一の式がないため、これは非効率的にcycle xsなります。したがって、結果のリストは、トラバースされるたびに継続的に構築され、より多くのメモリが割り当てられ、毎回より多くの計算が行われる必要があります。

対照的に、実際の実装は次のようになります。

cycle xs = xs' where xs' = xs ++ xs'

ここで、名前xs'は入力リストの末尾に追加されるように再帰的に定義されます。この時間xs'は共有され、一度だけ評価されます。結果として得られる無限リストは、実際にはメモリ内の有限の循環リンク リストであり、ループ全体が評価されると、それ以上の作業は必要ありません。


一般に、GHC は関数をメモ化しません: 結果に名前を付けてそれを使用しない限り、与えられたfandxを使用するたびf xに再評価されます。どちらの場合でも、結果の値は同じになりますが、パフォーマンスは大幅に異なる場合があります。これはほとんどの場合、悲観化を避けるための問題です.GHCが物事をメモ化するのは簡単ですが、多くの場合、これは少量または存在しない量の速度を得るために大量のメモリを消費します.

反対に、共有された価値観は保持されます。計算に非常にコストがかかるデータ構造がある場合、それを構築した結果に名前を付け、それを使用して関数に渡すことで、異なるスレッドで同時に使用されたとしても、作業が重複しないようにします。

このように自分で物事を悲観することもできます。データ構造の計算が安価で大量のメモリを使用する場合は、構造全体への参照を共有しないようにする必要があります。後で使用する可能性があります。

于 2012-12-22T19:03:07.663 に答える
2

はい、ある程度です。問題は、Haskell が一般に値を早く計算できないことです (例: 例外が発生する場合)。そのため、値自体の代わりにサンク (値を計算するためのコード) を保持する必要がある場合があります。より多くのメモリを使用し、物事を遅くします。コンパイラはこれを回避できるケースを検出しようとしますが、すべてを検出することは不可能です。

于 2012-12-22T12:12:26.670 に答える