2009-07-07 4 views
6

Ich habe die folgende Funktion, die für die IO Monade spezifisch ist:Haskell: generische 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 

Beispiel Nutzung:

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

Prints "hello" einmal.

Ich möchte (ein Haustier ärgern), damit es für so viele Fälle wie möglich funktioniert (nicht nur in IO).

fand ich stateref auf Hackage und mit ihm mein Code wie folgt aussieht:

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

Gibt es eine Alternative für stateref oder einen besseren Weg, es zu benutzen, als ich es tat?

+1

Es sieht aus wie Sie versuchen Teil von http://sebfisch.github.com/explicit-sharing/ neu zu erfinden? (Keine schlechte Sache, ich möchte nur klarstellen.) – ephemient

+0

Ich glaube nicht, dass "Ärgernis" bedeutet, was Sie denken, dass es bedeutet. – ShreevatsaR

+0

@ephemient: Ich weiß über Explicit-Sharing. Aber wie ich es verstehe, erfordert es, dass mein Code innerhalb des Sharing Monad Transformers läuft, der nicht zu GLUT Callbacks passt (plain IO), es sei denn, ich lasse es in einem anderen Thread laufen. – yairchu

Antwort

6

Ich habe eine kitschige kleine MonadRef Klasse für ein paar separate Gelegenheiten für meinen eigenen persönlichen Gebrauch umgeschrieben und jemand hat wahrscheinlich einen auf Hackage, aber ich kann keinen finden, der mit anderem Gepäck unbelastet ist.

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

Dann ist es Ihre memoization Routine zu abstrahieren leicht

(obwohl Sie wahrscheinlich IORef in diesem Zusammenhang mit einem MVar ersetzen möchten.) [Edit: geklärte verbage]

+0

Hackage hat ähnliche Implementierungen in den "TypeCompose" - und "ArrayRef" -Paketen (gefunden mit hayoo) – yairchu

+1

Er ich denke, in sich abgeschlossen war der falsche Begriff, ich meinte "ohne ein Bündel von anderem Gepäck", also vielleicht unbelastet mit anderem Gepäck "wäre angemessener. =) –

+0

Wie auch immer, ich denke, ich werde es nur verallgemeinern, wenn das Bedürfnis tatsächlich entsteht .. :) – yairchu