2009-07-07 5 views
6

J'ai fait la fonction suivante qui est spécifique pour la monade IO:Haskell: générique 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 

Exemple d'utilisation:

main :: IO() 
main = do 
    p <- memoIO $ putStrLn "hello" 
    p 
    p 

copies "hello" une fois. Je voudrais (une bête noire) pour le faire fonctionner pour autant de cas que possible (pas seulement dans IO).

Je trouve stateref sur hackage et avec elle mon code ressemble à ceci:

{-# 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 

Y at-il une alternative pour stateref ou une meilleure façon de l'utiliser que moi?

+1

Il semble que vous essayons de réinventer une partie de http://sebfisch.github.com/explicit-sharing/? (Ce n'est pas une mauvaise chose, je voudrais juste clarifier.) – ephemient

+0

Je ne pense pas que "bête" signifie ce que vous pensez que cela signifie. – ShreevatsaR

+0

@ephemient: Je connais le partage explicite. Mais si je comprends bien, il faudra que mon code fonctionne à l'intérieur du transformateur monad de partage, qui ne correspondra pas aux callbacks GLUT (IO simple) à moins que je ne le fasse fonctionner dans un autre thread. – yairchu

Répondre

6

J'ai réécrit à quelques reprises une classe MonadRef pour mon usage personnel et quelqu'un en a probablement un sur Hackage, mais je ne peux pas en trouver un qui ne soit pas encombré d'autres bagages.

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 
    ... 

Ensuite, il est facile à abstraire votre routine de memoization (si vous voulez probablement remplacer IORef dans ce contexte avec un MVar.)

[Edit: verbage clarifié]

+0

Hackage a des implémentations similaires dans les paquets "TypeCompose" et "ArrayRef" (trouvés en utilisant hayoo) – yairchu

+1

Er Je suppose que autonome était le mauvais terme, je voulais dire «sans un tas d'autres bagages», alors peut-être «non encombré avec d'autres bagages "serait plus approprié. =) –

+0

de toute façon, je suppose que je vais aller avec généraliser seulement si le besoin se pose réellement .. :) – yairchu