I hizo la siguiente función que es específico para la mónada IO:Haskell: genérico IORef, MVar?
memoIO :: MonadIO m => m a -> IO (m a)
memoIO action = do
ref <- newMVar Nothing
return $ do
x <- maybe action return =<< liftIO (takeMVar ref)
liftIO . putMVar ref $ Just x
return x
Ejemplo de uso:
main :: IO()
main = do
p <- memoIO $ putStrLn "hello"
p
p
Prints "hello
" una vez.
Me gustaría (una locura) hacer que funcione en tantos casos como sea posible (no solo en IO).
He encontrado en stateref hackage y con ella mi código es el siguiente:
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, Rank2Types, UndecidableInstances #-}
import Data.MRef
class (NewMRef r m a, DefaultMRef r m a, PutMRef r m a, TakeMRef r m a) => MRef r m a
instance (NewMRef r m a, DefaultMRef r m a, PutMRef r m a, TakeMRef r m a) => MRef r m a
memo :: (MRef r m (Maybe a), Monad s) => (forall x. m x -> s x) -> s a -> m (s a)
memo liftFunc action = do
ref <- newDefaultMRef Nothing
return $ do
x <- maybe action return =<< liftFunc (takeDefaultMRef ref)
liftFunc . putDefaultMRef ref $ Just x
return x
¿Hay una alternativa para stateref o una mejor manera de utilizarlo de lo que hice?
Parece que están tratando de reinventar parte de http://sebfisch.github.com/explicit-sharing/? (No es algo malo, solo me gustaría aclararlo) – ephemient
No creo que "mal" signifique lo que piensas que significa. – ShreevatsaR
@ephemient: sé de compartir explícitamente. Pero, como entiendo, requerirá que mi código se ejecute dentro del transformador de mónada compartido, que no se ajustará a las devoluciones de llamada GLUT (IO normal) a menos que lo haga funcionar en otro hilo. – yairchu