Unsaferperformioの一般的な使用を回避する方法
-
07-09-2020 - |
質問
Haskellコードでこのパターンを見つけることがよくあります:
options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar
...
doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
opt <- readMVar options
doSomething' where ...
.
基本的には、最初にプログラムの始まりに設定されているオプションまたは似たものの記録を持っています。プログラマーが怠惰なので、彼はプログラム全体のoptions
レコードを携帯したくないです。彼はそれを維持するためのMVar
を定義します - unsafePerformIO
の醜い使用によって定義されます。プログラマーは、状態が一度だけ設定され、操作が行われる前に設定されます。これで、プログラムの各部分は、オプションを抽出するためだけにunsafePerformIO
を再び使用する必要があります。
私の意見では、そのような変数は実用的に純粋な(私を倒さないで)と考えられています。この概念を抽象化し、変数が一度だけ設定されている、すなわちその初期化の前に呼び出しが行われず、unsafeFireZeMissilesAndMakeYourCodeUglyAnd
DisgustingBecauseOfThisLongFunctionName
解決
設定を保持するためにMVARを使用している場合、または似たものは、読者のモナドを試してみませんか?
foo :: ReaderT OptionRecord IO ()
foo = do
options <- ask
fireMissiles
main = runReaderT foo (OptionRecord "foo")
.
(およびIOを必要としない場合は通常のリーダー:P)
他のヒント
少しの重要な参照透明性を取引するもの 一時的な利便性はどちらでも値に値する 純度や便利さ。
これは悪い考えです。あなたが見つけているコードは不良コードです。*
安全なパターンではないため、このパターンを安全に包む方法はありません。あなたのコードでこれをしないでください。これを行うための安全な方法を探さないでください。これを行うための安全な方法はありません。unsafePerformIO
を床にゆっくりとコンソールから離れて置く...
*人々が最高レベルのMVARを使用する合意上の理由がありますが、これらの理由は、ほとんどの部分、またはその代替案が非常に厄介である他のいくつかのものへのバインディングと関係がある必要があります。しかしながら、それらの例では、私が知っている限りでは、最上位のMVARSはではなく、unsafePerformIO
の後ろからアクセスされていないです。
暗黙のパラメータを使用します。すべての機能にReader
またはReaderT
がその種類にあることよりもわずかに低い重量が少なくなります。機能のタイプ署名を変更する必要がありますが、そのような変更をスクリプト化できると思います。(Haskell IDEのための素晴らしい機能を作るだろう)
このパターンを使用しないことが重要な理由があります。私が知っている限り、
options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar
.
Haskellは、options
が一度だけ評価されることを保証しません。 option
の結果は純粋な値であるため、メモリ化され再利用できますが、すべての呼び出し(すなわちインライン)ごとに再計算することもでき、プログラムの意味は(あなたのケースとは反対に)変更してはいけません。
このパターンを使用する場合は、 {-# NOINLINE options #-}
を追加してください。それ以外の場合は、インライン化され、プログラムは失敗する可能性があります。 (そしてこれによって私達は言語とタイプシステムによって与えられた保証から出て、特定のコンパイラの実装だけに頼ります。)
このトピックは広く議論され、可能な解決策は上位レベル変異状態。現在、追加のコンパイラサポートなしでこのパターンを安全に抽象化することはできません。
Haskellコードでこのパターンを見つけることがよくあります:
異なるコードを読み取る
プログラマが怠惰なので、彼はプログラム全体のオプションレコードを運ぶことを望みません。彼はそれを維持するためのMVARを定義します - Ugly UseperFormioの醜い使用によって定義されます。プログラマーは、状態が一度だけ設定され、操作が行われる前に設定されます。これで、プログラムの各部分は、オプションを抽出するためだけにUnsafeperFormioを再度使用する必要があります。
は文字通り読者のモナドが何を達成するかを文字通り正確に鳴らしますが、読者のモナドは安全な方法でそれをします。あなた自身の怠惰を収容する代わりに、実際の良いコードを書くだけです。