I believe the intention is to ensure that two threads do not perform the action at the same time. If you look at the implementation of mfix for IO[1], it's using an MVar. I'm not 100% certain, but I think the `cache` function above could be rewritten to use MVars explicitly and avoid both monadic do and unsafe IO functions.

[1] The fixIO function, https://www.stackage.org/haddock/lts-10.3/base-4.10.1.0/src/System-IO.html#fixIO

On Thu, Jan 25, 2018 at 11:50 AM, Yotam Ohad <yotam2206@gmail.com> wrote:
Hi,

I've been digging around the source code of reactive-banana and I found this code:
data Cached m a = Cached (m a)

runCached :: Cached m a -> m a
runCached (Cached x) = x

-- | An action whose result will be cached.
-- Executing the action the first time in the monad will
-- execute the side effects. From then on,
-- only the generated value will be returned.
{-# NOINLINE cache #-}
cache :: (MonadFix m, MonadIO m) => m a -> Cached m a
cache m = unsafePerformIO $ do
    key <- liftIO $ newIORef Nothing
    return $ Cached $ do
        ma <- liftIO $ readIORef key    -- read the cached result
        case ma of
            Just a  -> return a         -- return the cached result.
            Nothing -> mdo
                liftIO $                -- write the result already
                    writeIORef key (Just a)
                a <- m                  -- evaluate
                return a

I'm trying to understand the reasom behind the use of mdo. Can't it be like this:
do
 a <- m
 liftIO $ writeIORef key (Just a)
 return a
Removing the need for a recursive definition?

Yotam

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.