Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I think optimally, with a set of typeclasses, one could define instances for IO and just use things with no interpretation or build a datastructure with free monads to perform whatever other inspections or manipulations you want. There could be some incompatability between the two notions that I'm missing, though...


I think I've seen the typeclass route as well before. It may have just been a blog post and not a library implementation, though. The two methods have different epistemological ideas, but could be combined. For instance:

    {-# LANGUAGE DeriveFunctor, GeneralizedNewtypeDeriving, FlexibleInstances #-}
    module CrWr where
    
    import Control.Monad.Free
    import Data.IORef
    
    data RWRefF t a = NewRef t (IORef t -> a) | PeekRef (IORef t) (t -> a) | PutRef (IORef t) t a
                    deriving Functor
    newtype RWRef t a = RWRef (Free (RWRefF t) a) deriving Monad
    
    newRef :: t -> RWRef t (IORef t)
    newRef t = RWRef $ liftF $ NewRef t id
    peekRef :: IORef t -> RWRef t t
    peekRef r = RWRef $  liftF $ PeekRef r id
    putRef :: IORef t -> t -> RWRef t ()
    putRef r t = RWRef $ liftF $ PutRef r t ()
    
    interpret :: RWRef t a -> IO a
    interpret (RWRef (Pure a)) = return a
    interpret (RWRef (Free (NewRef t f))) = newIORef t >>= interpret . RWRef . f
    interpret (RWRef (Free (PeekRef r f))) = readIORef r >>= interpret . RWRef . f
    interpret (RWRef (Free (PutRef r t next))) = writeIORef r t >> interpret (RWRef next)
    
    -- Highly specialized class of IO monads
    class Monad m => RWIntRefMonad m where
      new  :: Int -> m (IORef Int)
      peek :: IORef Int -> m Int
      put  :: IORef Int -> Int -> m ()
      toIO :: m a -> IO a
    
    instance RWIntRefMonad (RWRef Int) where
      new = newRef
      peek = peekRef
      put = putRef
      toIO = interpret
    
    incr :: RWIntRefMonad m => IORef Int -> m ()
    incr r = peek r >>= put r . (+1)
    
    main = do r <- newIORef 0
              -- We need to specialize before the m gets erased
              toIO (incr r :: RWRef Int ())
              readIORef r >>= print




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: