module Data.Once (Once, newOnce, runOnce) where


import           Control.Concurrent.MVar
import           Control.Monad
import           Control.Monad.IO.Class


newtype Once m a = Once (MVar (m a))


newOnce :: MonadIO m => m a -> m (Once m a)
newOnce = liftIO . fmap Once . newMVar


runOnce :: MonadIO m => Once m a -> m a
runOnce (Once io) = do
  x <- join (liftIO $ takeMVar io)
  x <$ liftIO (putMVar io (return x))