content: {-# OPTIONS_JHC -fno-prelude  #-}
  module Jhc.ACIO where
  
  import Jhc.IORef
  import Jhc.IO
  import Jhc.Monad
  
  newtype ACIO a = ACIO (IO a)
      deriving(Monad,Functor)
  
  unsafeIOToACIO :: IO a -> ACIO a
  unsafeIOToACIO x = ACIO x
  
  acioToIO :: ACIO a -> IO a
  acioToIO (ACIO x) = x
  
  newIORefAC :: a -> ACIO (IORef a)
  newIORefAC a = unsafeIOToACIO (newIORef a)
  
  runOnce :: IO a -> ACIO (IO a)
  runOnce action = do
      ref <- newIORefAC Nothing
      return $ do
          v <- readIORef ref
          case v of
              Just v -> return v
              Nothing -> do
                  v <- action
                  writeIORef ref v
                  return v
  
  {- @Extensions
  
  # Top Level Actions
  
  Jhc supports monadic actions declared at the top level of your module. These
  can be used to do things such as initialize IORefs or allocate static data. An example
  of a top level action is the following.
  
      import Jhc.ACIO
      import Data.IORef
  
      ref <- newIORefAC 0
  
      count = do
          modifyIORef ref (1 +)
          readIORef ref >>= print
  
      main = do
          count
          count
          count
  
  Which will print 1, 2, and 3. A special monad ACIO (which stands for Affine
  Central IO) is provided to restrict what may take place in top level actions.
  Basically, top level actions can only consist of IO that can be omitted or
  reordered without changing the meaning of a program. In practice, this means
  that it does not matter whether such actions are all performed at the beginning
  or are only computed once on demand.
  
  If you need to use arbitrary IO, a utility function 'runOnce' is provided.
  using it you can ensure arbitrary IO actions are run only once and the return
  values shared, however you must access the value inside the IO monad, thus
  ensuring program integrity. An example using a hypothetical GUI library is below.
  
      import Jhc.ACIO
  
      getWindow <- runOnce $ do
          connection <- newGUIConnection
          window <- createWindow (640,480)
          setTitle window "My Global Window"
          return window
  
      main = do
          w <- getWindow
          draw w "Hello!"
  
  Note, top level global variables can be indicative of design issues. In
  general, they should only be used when necessary to interface with an external
  library, opaque uses inside a library where the shared state can not be
  externally observed, or inside your Main program as design dictates.
  
  -}
  