19

Haskell コードでこのパターンをよく見かけます。

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

...

doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
  opt <- readMVar options
  doSomething' where ...

基本的に、プログラムの開始時に最初に設定されたオプションなどの記録があります。optionsプログラマーは怠け者なので、プログラム全体に記録を残したくありません。彼はそれMVarを維持するために を定義しています - の醜い使い方によって定義されていますunsafePerformIO。プログラマーは、操作が行われる前に状態が一度だけ設定されるようにします。unsafePerformIOここで、オプションを抽出するためだけに、プログラムの各部分を再度使用する必要があります。

私の意見では、そのような変数は実用的に純粋であると考えられています(私を打ち負かさないでください)。この概念を抽象化し、変数が一度だけ設定されるようにするライブラリがありますか。つまり、その初期化の前に呼び出しが行われず、書き込む必要がないことを保証しますunsafeFireZeMissilesAndMakeYourCodeUglyAnd DisgustingBecauseOfThisLongFunctionName

4

5 に答える 5

21

本質的な参照透過性を少しの一時的な利便性と引き換えにする人は、純粋性も利便性も得られません。

これは悪い考えです。これが見つかったコードは悪いコードです。*

このパターンは安全なパターンではないため、安全に完全にラップする方法はありません。コードでこれを行わないでください。これを行うための安全な方法を探してはいけません。これを行う安全な方法はありません。unsafePerformIOゆっくりとダウンを床に置き、コンソールから離します...

*人々がトップ レベルの MVar を使用するのには正当な理由がありますが、それらの理由のほとんどは、外部コードへのバインド、または代替手段が非常に厄介な他のいくつかのことと関係があります。ただし、そのような場合、私の知る限り、最上位の MVar は背後からアクセスされませんunsafePerformIO

于 2011-05-20T18:38:23.747 に答える
10

MVar を設定の保持などに使用している場合は、reader モナドを試してみませんか?

foo :: ReaderT OptionRecord IO ()
foo = do
    options <- ask
    fireMissiles

main = runReaderT foo (OptionRecord "foo")

(そして、IO を必要としない場合は通常の Reader :P)

于 2011-05-20T18:37:17.643 に答える
5

暗黙的なパラメーターを使用します。Readerそれらは、すべての関数にその型を持たせるかReaderT、その型にするよりもわずかに軽量です。関数の型シグネチャを変更する必要がありますが、そのような変更はスクリプト化できると思います。(Haskell IDE の優れた機能になるでしょう。)

于 2011-05-20T19:43:51.277 に答える
2

このパターンを使用しない重要な理由があります。私の知る限りでは、

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

Haskell は、options一度だけ評価されることを保証しません。の結果optionは純粋な値であるため、メモ化して再利用できますが、呼び出しごとに再計算することもでき (つまり、インライン化)、プログラムの意味を変更してはなりません (ケースに反して)。

それでもこのパターンを使用する場合は、必ず を追加し {-# NOINLINE options #-}てください。そうしないと、インライン化されてプログラムが失敗する可能性があります。(これにより、言語と型システムによって与えられる保証から抜け出し、特定のコンパイラの実装のみに依存することになります。)

このトピックは広く議論されており、可能な解決策は Haskell Wiki のTop level mutable stateにうまくまとめられています。現在、追加のコンパイラ サポートなしに、このパターンを安全に抽象化することはできません。

于 2014-05-24T06:49:34.557 に答える