関数のスコープで新しいバインディングを提供しているlet funcs = aux
だけです。つまり、で参照しているのはグローバルスコープのもの、つまり として定義されているものです。純粋な値は、グローバルであろうとなかろうと、実行時に変更することはできません。ただし、変更可能な参照を使用することは可能です。できればローカルに、しかし少し危険なハッカーを使ってグローバルに。funcs
f
funcs
g
Map.empty
しかし、グローバル変数を使用することは本当に必要ですか? プログラム全体でグローバルを使用していない場合は、State
代わりにそれを使用するすべての計算をモナドでラップすることをお勧めします。
import Control.Monad.State
import qualified Data.Map as Map
funcs :: Map.Map String Double
funcs = Map.empty
f :: String -> Double -> State (Map.Map String Double) ()
f str d = do
funcs <- get
put (Map.insert str d funcs)
g :: State (Map.Map String Double) String
g = do
funcs <- get
if (Map.lookup "aaa" funcs) == Nothing then return "not defined" else return "ok"
main = putStrLn $ flip evalState funcs $ do {f "aaa" 1; g}
このように状態を制約しておくと、プログラムの成長を追跡しやすくなります。タイプによって明確に示されるため、どの計算が状態を変更する可能性があるかを常に知っています。
一方、何らかの理由でグローバル変数が絶対に必要な場合は、IORef
s とを使用したよく知られたかなり醜いトリックがありunsafePerformIO
ます。
import Data.IORef
import System.IO.Unsafe
import qualified Data.Map as Map
{-# NOINLINE funcs #-}
funcs :: IORef (Map.Map String Double)
funcs = unsafePerformIO $ newIORef Map.empty
f :: String -> Double -> IO ()
f str d = atomicModifyIORef funcs (\m -> (Map.insert str d m, ()))
g :: IO ()
g = do
fs <- readIORef funcs
if (Map.lookup "aaa" fs) == Nothing then error "not defined" else putStrLn "ok"
main = do
f "aaa" 1
g
このトリックは、モナドIORef
内で読み取りと更新が可能な global を作成します。IO
これは、IO を実行する計算によってグローバルの値が変更される可能性があることを意味します。これにより、グローバルな状態のすばらしい頭痛の種がすべて与えられます。それとは別に、このトリックも非常にハックであり、GHC の実装の詳細のためにのみ機能します ({-# NOINLINE funcs #-}
たとえば、その部分を参照してください)。
このハックを使用することに決めた場合 (私は絶対に使用しないことをお勧めします)、ポリモーフィックな値では絶対に使用できないことに注意してください。理由を説明するには:
import Data.IORef
import System.IO.Unsafe
{-# NOINLINE danger #-}
danger :: IORef a
danger = unsafePerformIO $ newIORef undefined
coerce :: a -> IO b
coerce x = do
writeIORef danger x
readIORef danger
main = do
x <- coerce (0 :: Integer) :: IO (Double, String) -- boom!
print x
ご覧のとおり、このトリックをポリモーフィズムと一緒に使用して、任意の型を他の型として再解釈する関数を作成できます。これは明らかに型の安全性を破り、プログラムにセグメンテーション違反を引き起こす可能性があります (せいぜい)。
要約すると、グローバル変数の代わりにモナドを使用することを検討してください。グローバル変数を軽視しないでください。State