haskell-jp / random #101 at 2022-12-14 19:04:35 +0900

こんなグローバル変数作るための unsafePerformIO は許せるかどうか
foo = unsafePerformIO $ newIORef Foo

デバッグ用のライブラリーで見たことあります
グローバルといってもpureな関数ではその値は読めなくて、IOモナドでは読めるので、必要が有ればいいといいたいですね。
他の方法よりも利便性が圧倒的に高いような用途であって、
• NOINLINEなどの必要なpragmaをつける
• 型を単相にする
などの必要な安全策を取るのであればアリだと思ってます。
ありがとうございます!
前はナシかな~と思ってたんですけど、最近はまあいいかみたいな気持ちで揺れてたので聞いてみました
コマンドラインオプションの情報とかは、プログラム実行中にはただの定数なのに IO モナドが必要というジレンマがあるのでこの書き方がぴったりくる気がしますね
(<@U56MBRKR9> さんの古い記事にもありました https://kazu-yamamoto.hatenablog.jp/entry/20090107/1231318138 )。
うーん、optparse-applicativeとかで普通にunsafePerformIOを使わずにコマンドラインオプションのパースができていることを考えると、ちょっとその情報は古いと思いますね
情報ありがとうございます。なんか古そうだなとは思っていたので、新鮮な情報がいただけるのはありがたいです。
でも、問題の本質は「オプションのパース」の部分ではなくて、「パースされた結果をプログラム中の任意の場所で参照したい」の方なので、まだ unsafePerformIO の利便性はあるのでは?という意図でした
そういう目的でしたら ReaderT IO の出番ですね。そりゃぁ unsafePerformIO でグローバル変数を作る方が楽でしょうけど、普通のグローバル変数同様テストしやすさや再利用性が落ちますし、よほど手を抜きたいとき以外は避けたい手段ですね
最初はとりあえずハードコーディングでグローバル定数で記述していた設定値を、あとからコマンドラインパラメータ化する、とかいうときに、 ReaderT IO 化すると書き直す場所が多くて大変ではないでしょうかね?
そこはトレードオフですね
unsafePerformIO のグローバル変数がどこらへんまで許せるかどうかという文脈だったので、コマンドラインパラメータを運ぶのは比較的許容しやすいんじゃないかなあ、という例でございました^^;
僕たちが作っているdnsextでは、Showのインスタンスを拡張可能にするために、黒魔術を使っています。
https://github.com/kazu-yamamoto/dnsext/blob/main/dnsext-types/DNS/Types/Type.hs#L124
なんと言いましても、GHCの実現に unsafePerformIO が多用されているので、Haskellerが高尚なことを言うのは、ブーメランだと思われます。。。
それこそ、別にunsafePerformIOに限らずGHCが汚いことをしている分せめて我々ユーザーはちゃんとしよう、とも言えるかと。その手の主張をし出すと大抵の「高尚な努力」を否定することになるので不快です :disappointed:
すいません。
実際、以前にHaskellerがOCamlerからブーメランを受けたことがあるので。。。