Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>With <code>let funcs = aux</code> you're only giving <code>funcs</code> a new binding in the scope of the <code>f</code> function, which means that the <code>funcs</code> you're referring to in <code>g</code> is the one in the global scope - the one that's defined as <code>Map.empty</code>. It is not possible to change pure values, global or otherwise, at runtime. It is, however, possible to use mutable references. Preferrably locally, but also globally with a bit of unsafe hackery.</p> <p>Is it <em>really</em> necessary to use a global variable though? If you're not using your global throughout your entire program, you may want to wrap all the computations that use it in a <code>State</code> monad instead:</p> <pre><code>import Control.Monad.State import qualified Data.Map as Map funcs :: Map.Map String Double funcs = Map.empty f :: String -&gt; Double -&gt; State (Map.Map String Double) () f str d = do funcs &lt;- get put (Map.insert str d funcs) g :: State (Map.Map String Double) String g = do funcs &lt;- get if (Map.lookup "aaa" funcs) == Nothing then return "not defined" else return "ok" main = putStrLn $ flip evalState funcs $ do {f "aaa" 1; g} </code></pre> <p>Keeping your state constrained in this way makes it easier to keep track of your program as it grows; you always know which computations may alter your state as it's clearly indicated by its type.</p> <p>If, on the other hand, you for some reason absolutely need global variables, there is a well-known but fairly ugly trick using <code>IORef</code>s and <code>unsafePerformIO</code>:</p> <pre><code>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 -&gt; Double -&gt; IO () f str d = atomicModifyIORef funcs (\m -&gt; (Map.insert str d m, ())) g :: IO () g = do fs &lt;- readIORef funcs if (Map.lookup "aaa" fs) == Nothing then error "not defined" else putStrLn "ok" main = do f "aaa" 1 g </code></pre> <p>This trick creates a global <code>IORef</code>, which can be read and updated inside the <code>IO</code> monad. This means that any computation that performs IO may change the value of your global, which gives you all the wonderful headaches of global state. Aside from that, this trick is also extremely hacky and only works because of implementation details in GHC (see the <code>{-# NOINLINE funcs #-}</code> part, for instance).</p> <p>If you decide to use this hack (which I <strong>really</strong> recommend against), keep in mind that you can <strong>absolutely not</strong> use it with polymorphic values. To illustrate why:</p> <pre><code>import Data.IORef import System.IO.Unsafe {-# NOINLINE danger #-} danger :: IORef a danger = unsafePerformIO $ newIORef undefined coerce :: a -&gt; IO b coerce x = do writeIORef danger x readIORef danger main = do x &lt;- coerce (0 :: Integer) :: IO (Double, String) -- boom! print x </code></pre> <p>As you can see, this trick can be used together with polymorphism to write a function that <em>reinterprets any type as any other type</em>, which obviously breaks type safety and so may cause your programs to segfault (at best).</p> <p>In summary, <strong>do</strong> consider using the <code>State</code> monad instead of global variables; <strong>do not</strong> turn to global variables lightly.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload