2009-07-07 9 views
6

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?

+1

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

+0

No creo que "mal" signifique lo que piensas que significa. – ShreevatsaR

+0

@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

Respuesta

6

He reescrito una pequeña clase cursi MonadRef en algunas ocasiones para mi uso personal y alguien probablemente tiene una en Hackage, pero no puedo encontrar una que no esté cargada con otro equipaje.

class Monad m => MonadRef m where 
    type Ref m :: * -> * 
    newRef :: a -> Ref m a 
    writeRef :: Ref m a -> -> m() 
    readRef :: Ref m a -> m a 

instance MonadRef IO where 
    type Ref IO = IORef 
    newRef = newIORef 
    writeRef = writeIORef 
    readRef = writeIORef 

instance MonadRef STM where 
    type Ref STM = TVar 
    ... 


instance MonadRef (ST s) where 
    type Ref (ST s) = STRef s 
    ... 

entonces es fácil abstraer su rutina memoization (aunque es probable que desee para reemplazar IORef en este contexto con un MVar.)

[Editar: aclarado verbage]

+0

Hackage tiene implementaciones similares en los paquetes "TypeCompose" y "ArrayRef" (que se encuentran usando hayoo) – yairchu

+1

Er Supongo que autónomo era el término equivocado, quise decir "sin un montón de otros equipajes", por lo que tal vez "sin otro equipaje". 'sería más apropiado. =) –

+0

de todos modos, supongo que voy a generalizarlo solo si realmente surge la necesidad ... :) – yairchu