module System.Timeout.Returning.Writer (
MonadWriter(..),
MonadTimeout(..),
MonadTimeoutWriter(..),
TimeoutWriter(),
runTimeout,
withTimeoutWriter,
Last'(..),
SeqMax(..),
NFMonoid(..),
defaultListen,
defaultPass
) where
import Control.Applicative
import Control.Monad
import Control.Monad.Reader
import Control.Monad.Writer
import qualified Control.Concurrent as C
import Control.Concurrent.MVar
import Control.DeepSeq (NFData(..))
import Control.Seq
import Data.Monoid
import qualified System.Timeout as T
class (Monad m) => MonadTimeout w m | m -> w where
partialResult :: w -> m ()
yield :: m ()
yield = return ()
class (Monoid w, MonadTimeout w m, MonadWriter w m)
=> MonadTimeoutWriter w m | m -> w where
contained :: m r -> m (r, w)
contained k = do
~(_, zero) <- listen (return ())
pass (listen k >>= \x -> return (x, const zero))
defaultListen :: MonadTimeoutWriter w m => m a -> m (a, w)
defaultListen k = do
(x, w) <- contained k
tell w
return (x, w)
defaultPass :: MonadTimeoutWriter w m => m (a, w -> w) -> m a
defaultPass k = do
((x, f), w) <- contained k
tell (f w)
return x
newtype TimeoutWriter w a
= TimeoutWriter { getTimeoutWriter :: ReaderT (w -> IO ()) IO a }
instance Functor (TimeoutWriter w) where
fmap = liftM
instance Applicative (TimeoutWriter w) where
pure = return
(<*>) = ap
instance Monad (TimeoutWriter w) where
return = TimeoutWriter . return
(TimeoutWriter v) >>= f = TimeoutWriter (v >>= (getTimeoutWriter . f))
instance MonadIO (TimeoutWriter w) where
liftIO = TimeoutWriter . lift
instance Monoid w => MonadWriter w (TimeoutWriter w) where
tell = partialResult
listen = defaultListen
pass = defaultPass
instance Monoid w => MonadTimeout w (TimeoutWriter w) where
partialResult x = TimeoutWriter $ ask >>= \r -> lift (r x)
yield = liftIO C.yield
instance Monoid w => MonadTimeoutWriter w (TimeoutWriter w) where
contained = liftIO . runTimeoutInternal id
withTimeoutWriter :: (w' -> w) -> (TimeoutWriter w' a -> TimeoutWriter w a)
withTimeoutWriter f (TimeoutWriter k) = TimeoutWriter $ withReaderT (. f) k
runTimeout
:: Monoid w
=> Int
-> TimeoutWriter w r
-> IO (Maybe r, w)
runTimeout duration = runTimeoutInternal (T.timeout duration)
runTimeoutInternal
:: Monoid w
=> (IO r -> IO a)
-> TimeoutWriter w r
-> IO (a, w)
runTimeoutInternal run (TimeoutWriter k) = do
mvar <- newMVar mempty
let save x = modifyMVar_ mvar (return . withStrategy rseq . (`mappend` x))
r <- run (runReaderT k save)
w <- takeMVar mvar
return (r, w)
sseq :: Strategy a -> a -> b -> b
sseq s x y = s x `seq` y
newtype Last' a = Last' { getLast' :: Maybe a }
deriving (Eq, Ord, Show, Read)
instance Functor Last' where
fmap f (Last' x) = Last' $ fmap f x
instance NFData a => NFData (Last' a) where
rnf (Last' x) = rnf x
instance Monoid (Last' a) where
mempty = Last' Nothing
mappend (Last' x) (Last' y)
= Last' $ getLast (Last x `mappend` Last y)
newtype SeqMax a b = SeqMax (Maybe (a, b))
deriving (Eq, Ord, Show, Read)
instance Functor (SeqMax a) where
fmap f (SeqMax x) = SeqMax $ fmap (fmap f) x
instance (NFData a, NFData b) => NFData (SeqMax a b) where
rnf (SeqMax x) = rnf x
instance (Ord b) => Monoid (SeqMax a b) where
mempty = SeqMax Nothing
mappend (SeqMax Nothing) s = s
mappend s (SeqMax Nothing) = s
mappend m1@(SeqMax (Just (r1, x1))) m2@(SeqMax (Just (r2, x2)))
| x1 >= x2 = sseq rseq r1 m1
| otherwise = sseq rseq r2 m2
newtype NFMonoid a = NFMonoid { getNFMonoid :: a }
deriving (Eq, Ord, Show, Read, Bounded)
instance Functor NFMonoid where
fmap f (NFMonoid x) = NFMonoid (f x)
instance (NFData a, Monoid a) => Monoid (NFMonoid a) where
mempty = NFMonoid mempty
mappend (NFMonoid x) (NFMonoid y)
= NFMonoid ((x `mappend` y) `using` rdeepseq)