-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Haskus utility modules -- -- Haskus utility modules. @package haskus-utils @version 1.5 module Haskus.Utils.Dynamic -- | Dynamic type with Eq and Ord instance -- -- Can be used as Map keys for instance data DynEq [DynEq] :: forall a. (Eq a, Ord a) => TypeRep a -> a -> DynEq -- | Create a DynEq value -- --
-- >>> toDynEq (10 :: Int) == toDynEq (12 :: Int) -- False -- -- >>> toDynEq (10 :: Int) <= toDynEq (12 :: Int) -- True -- -- >>> toDynEq (10 :: Int) /= toDynEq "Test" -- True --toDynEq :: (Typeable a, Eq a, Ord a) => a -> DynEq -- | Get a value from a DynEq or the default one if the type doesn't match fromDynEq :: Typeable a => DynEq -> a -> a -- | Get a value from a DynEq if the type matches fromDynEqMaybe :: forall a. Typeable a => DynEq -> Maybe a instance GHC.Classes.Eq Haskus.Utils.Dynamic.DynEq instance GHC.Classes.Ord Haskus.Utils.Dynamic.DynEq -- | Embed data into the executable binary module Haskus.Utils.Embed -- | Embed bytes in a C array, return an Addr# embedBytes :: [Word8] -> Q Exp -- | A quasiquoter for raw string literals - that is, string literals that -- don't recognise the standard escape sequences (such as '\n'). -- Basically, they make your code more readable by freeing you from the -- responsibility to escape backslashes. They are useful when working -- with regular expressions, DOS/Windows paths and markup languages (such -- as XML). -- -- Don't forget the LANGUAGE QuasiQuotes pragma if you're using -- this module in your code. -- -- Usage: -- --
-- :set -XQuasiQuotes
-- import Haskus.Utils.Embed
-- let s = [raw|\\w+\@[a-zA-Z_]+?\\.[a-zA-Z]{2,3}|]
-- s
--
--
-- "\\w+@[a-zA-Z_]+?\\.[a-zA-Z]{2,3}" > [raw|C:\Windows\SYSTEM|] ++
-- [raw|\user32.dll|] "C:\\Windows\\SYSTEM\\user32.dll"
--
-- Multiline raw string literals are also supported:
--
-- -- multiline :: String -- multiline = [raw|<HTML> -- <HEAD> -- <TITLE>Auto-generated html formated source</TITLE> -- <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252"> -- </HEAD> -- <BODY LINK="800080" BGCOLOR="#ffffff"> -- <P> </P> -- <PRE>|] ---- -- Caveat: since the "|]" character sequence is used to -- terminate the quasiquotation, you can't use it inside the raw string -- literal. Use rawQ if you want to embed that character sequence -- inside the raw string. raw :: QuasiQuoter -- | A variant of raw that interprets the "|~]" sequence as -- "|]", "|~~]" as "|~]" and, in general, -- "|~^n]" as "|~^(n-1)]" for n >= 1. -- -- Usage: -- --
-- [rawQ||~]|~]|] ---- -- "|]|]" -- --
-- [rawQ||~~]|] ---- -- "|~]" -- --
-- [rawQ||~~~~]|] ---- -- "|~~~]" rawQ :: QuasiQuoter -- | Control-flow module Haskus.Utils.Flow -- | Monads in which IO computations may be embedded. Any monad -- built by applying a sequence of monad transformers to the IO -- monad will be an instance of this class. -- -- Instances should satisfy the following laws, which state that -- liftIO is a transformer of monads: -- -- class Monad m => MonadIO (m :: Type -> Type) -- | Lift a computation from the IO monad. liftIO :: MonadIO m => IO a -> m a class MonadIO m => MonadInIO (m :: Type -> Type) -- | Lift with*-like functions into IO (alloca, etc.) liftWith :: MonadInIO m => (forall c. () => (a -> IO c) -> IO c) -> (a -> m b) -> m b -- | Lift with*-like functions into IO (alloca, etc.) liftWith2 :: MonadInIO m => (forall c. () => (a -> b -> IO c) -> IO c) -> (a -> b -> m e) -> m e -- | Compose functions -- --
-- >>> (+1) >.> (*7) <| 1 -- 14 --(>.>) :: (a -> b) -> (b -> c) -> a -> c infixl 9 >.> -- | Compose functions -- --
-- >>> (+1) <.< (*7) <| 1 -- 8 --(<.<) :: (b -> c) -> (a -> b) -> a -> c infixr 9 <.< -- | Apply a function -- --
-- >>> 5 |> (*2) -- 10 --(|>) :: a -> (a -> b) -> b infixl 0 |> -- | Apply a function -- --
-- >>> (*2) <| 5 -- 10 --(<|) :: (a -> b) -> a -> b infixr 0 <| -- | Apply a function in a Functor -- --
-- >>> Just 5 ||> (*2) -- Just 10 --(||>) :: Functor f => f a -> (a -> b) -> f b infixl 0 ||> -- | Apply a function in a Functor -- --
-- >>> (*2) <|| Just 5 -- Just 10 --(<||) :: Functor f => (a -> b) -> f a -> f b infixr 0 <|| -- | Apply a function in a Functor -- --
-- >>> Just [5] |||> (*2) -- Just [10] --(|||>) :: (Functor f, Functor g) => f (g a) -> (a -> b) -> f (g b) infixl 0 |||> -- | Apply a function in a Functor -- --
-- >>> (*2) <||| Just [5] -- Just [10] --(<|||) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b) infixr 0 <||| -- | Conditional execution of Applicative expressions. For example, -- --
-- when debug (putStrLn "Debugging") ---- -- will output the string Debugging if the Boolean value -- debug is True, and otherwise do nothing. when :: Applicative f => Bool -> f () -> f () -- | The reverse of when. unless :: Applicative f => Bool -> f () -> f () -- | Like when, but where the test can be monadic. whenM :: Monad m => m Bool -> m () -> m () -- | Like unless, but where the test can be monadic. unlessM :: Monad m => m Bool -> m () -> m () -- | Like if, but where the test can be monadic. ifM :: Monad m => m Bool -> m a -> m a -> m a -- | Conditional failure of Alternative computations. Defined by -- --
-- guard True = pure () -- guard False = empty ---- --
-- >>> safeDiv 4 0 -- Nothing -- >>> safeDiv 4 2 -- Just 2 ---- -- A definition of safeDiv using guards, but not guard: -- --
-- safeDiv :: Int -> Int -> Maybe Int -- safeDiv x y | y /= 0 = Just (x `div` y) -- | otherwise = Nothing ---- -- A definition of safeDiv using guard and Monad -- do-notation: -- --
-- safeDiv :: Int -> Int -> Maybe Int -- safeDiv x y = do -- guard (y /= 0) -- return (x `div` y) --guard :: Alternative f => Bool -> f () -- | void value discards or ignores the result of -- evaluation, such as the return value of an IO action. -- --
-- >>> void Nothing -- Nothing -- -- >>> void (Just 3) -- Just () ---- -- Replace the contents of an Either Int -- Int with unit, resulting in an Either -- Int '()': -- --
-- >>> void (Left 8675309) -- Left 8675309 -- -- >>> void (Right 8675309) -- Right () ---- -- Replace every element of a list with unit: -- --
-- >>> void [1,2,3] -- [(),(),()] ---- -- Replace the second element of a pair with unit: -- --
-- >>> void (1,2) -- (1,()) ---- -- Discard the result of an IO action: -- --
-- >>> mapM print [1,2] -- 1 -- 2 -- [(),()] -- -- >>> void $ mapM print [1,2] -- 1 -- 2 --void :: Functor f => f a -> f () -- | Repeat an action indefinitely. -- --
-- echoServer :: Socket -> IO () -- echoServer socket = forever $ do -- client <- accept socket -- forkFinally (echo client) (\_ -> hClose client) -- where -- echo :: Handle -> IO () -- echo client = forever $ -- hGetLine client >>= hPutStrLn client --forever :: Applicative f => f a -> f b -- | The foldM function is analogous to foldl, except that -- its result is encapsulated in a monad. Note that foldM works -- from left-to-right over the list arguments. This could be an issue -- where (>>) and the `folded function' are not -- commutative. -- --
-- foldM f a1 [x1, x2, ..., xm] -- -- == -- -- do -- a2 <- f a1 x1 -- a3 <- f a2 x2 -- ... -- f am xm ---- -- If right-to-left evaluation is required, the input list should be -- reversed. -- -- Note: foldM is the same as foldlM foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b -- | Like foldM, but discards the result. foldM_ :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m () -- | forM is mapM with its arguments flipped. For a version -- that ignores the results see forM_. forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b) -- | forM_ is mapM_ with its arguments flipped. For a version -- that doesn't ignore the results see forM. -- -- As of base 4.8.0.0, forM_ is just for_, specialized to -- Monad. forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m () -- | Composition of catMaybes and forM -- --
-- >>> let f x = if x > 3 then putStrLn "OK" >> return (Just x) else return Nothing -- -- >>> forMaybeM [0..5] f -- OK -- OK -- [4,5] --forMaybeM :: Monad m => [a] -> (a -> m (Maybe b)) -> m [b] -- | Map each element of a structure to a monadic action, evaluate these -- actions from left to right, and collect the results. For a version -- that ignores the results see mapM_. mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b) -- | Map each element of a structure to a monadic action, evaluate these -- actions from left to right, and ignore the results. For a version that -- doesn't ignore the results see mapM. -- -- As of base 4.8.0.0, mapM_ is just traverse_, specialized -- to Monad. mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m () -- | Evaluate each monadic action in the structure from left to right, and -- collect the results. For a version that ignores the results see -- sequence_. sequence :: (Traversable t, Monad m) => t (m a) -> m (t a) -- | replicateM n act performs the action n times, -- gathering the results. replicateM :: Applicative m => Int -> m a -> m [a] -- | Like replicateM, but discards the result. replicateM_ :: Applicative m => Int -> m a -> m () -- | This generalizes the list-based filter function. filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a] -- | The join function is the conventional monad join operator. It -- is used to remove one level of monadic structure, projecting its bound -- argument into the outer level. -- --
-- atomically :: STM a -> IO a ---- -- is used to run STM transactions atomically. So, by specializing -- the types of atomically and join to -- --
-- atomically :: STM (IO b) -> IO (IO b) -- join :: IO (IO b) -> IO b ---- -- we can compose them as -- --
-- join . atomically :: STM (IO b) -> IO b ---- -- to run an STM transaction and the IO action it returns. join :: Monad m => m (m a) -> m a -- | Right-to-left composition of Kleisli arrows. -- (>=>), with the arguments flipped. -- -- Note how this operator resembles function composition -- (.): -- --
-- (.) :: (b -> c) -> (a -> b) -> a -> c -- (<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c --(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c infixr 1 <=< -- | Left-to-right composition of Kleisli arrows. (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c infixr 1 >=> -- | A monadic version of loop, where the predicate returns -- Left as a seed for the next loop or Right to abort the -- loop. loopM :: Monad m => (a -> m (Either a b)) -> a -> m b -- | Keep running an operation until it becomes False. As an -- example: -- --
-- whileM $ do sleep 0.1; notM $ doesFileExist "foo.txt" -- readFile "foo.txt" ---- -- If you need some state persisted between each test, use loopM. whileM :: Monad m => m Bool -> m () -- | forM_ with interspersed action -- --
-- >>> intersperseM_ (putStr ", ") ["1","2","3","4"] putStr -- 1, 2, 3, 4 --intersperseM_ :: Monad m => m () -> [a] -> (a -> m ()) -> m () -- | Fast for-loop in a Monad (more efficient than forM_ [0..n] for -- instance). -- --
-- >>> forLoopM_ (0::Word) (<5) (+1) print -- 0 -- 1 -- 2 -- 3 -- 4 --forLoopM_ :: Monad m => a -> (a -> Bool) -> (a -> a) -> (a -> m ()) -> m () -- | Fast fort-loop with an accumulated result -- --
-- >>> let f acc n = acc ++ (if n == 0 then "" else ", ") ++ show n -- -- >>> forLoop (0::Word) (<5) (+1) "" f -- "0, 1, 2, 3, 4" --forLoop :: a -> (a -> Bool) -> (a -> a) -> acc -> (acc -> a -> acc) -> acc -- | Lift a computation from the argument monad to the constructed monad. lift :: (MonadTrans t, Monad m) => m a -> t m a -- | Heterogeneous array: like a HList but indexed in O(1) module Haskus.Utils.HArray -- | heterogeneous array data HArray (types :: [*]) -- | The type t with index n is indexable in the array type HArrayIndex (n :: Nat) t (ts :: [*]) = (KnownNat n, t ~ Index n ts, KnownNat (Length ts), CmpNat n (Length ts) ~ 'LT) -- | A type t is indexable in the array type HArrayIndexT t (ts :: [*]) = (CheckMember t ts, HArrayIndex (IndexOf t ts) t ts) -- | A type t is maybe indexable in the array type HArrayTryIndexT t (ts :: [*]) = (HArrayIndex (MaybeIndexOf t ts) t (t : ts)) -- | Empty array emptyHArray :: HArray '[] -- | Empty array singleHArray :: a -> HArray '[a] -- | Get an element by index getHArrayN :: forall (n :: Nat) (ts :: [*]) t. HArrayIndex n t ts => HArray ts -> t -- | Get first element getHArray0 :: HArrayIndex 0 t ts => HArray ts -> t -- | Set an element by index setHArrayN :: forall (n :: Nat) (ts :: [*]) t. HArrayIndex n t ts => t -> HArray ts -> HArray ts -- | Get an element by type (select the first one with this type) getHArrayT :: forall t ts. HArrayIndexT t ts => HArray ts -> t -- | Set an element by type (select the first one with this type) setHArrayT :: forall t ts. HArrayIndexT t ts => t -> HArray ts -> HArray ts -- | Get an element by type (select the first one with this type) tryGetHArrayT :: forall t ts. HArrayTryIndexT t ts => HArray ts -> Maybe t -- | Append a value to an array (O(n)) appendHArray :: HArray ts -> t -> HArray (Snoc ts t) -- | Prepend a value to an array (O(n)) prependHArray :: t -> HArray ts -> HArray (t : ts) -- | Concat arrays concatHArray :: HArray ts1 -> HArray ts2 -> HArray (Concat ts1 ts2) -- | Drop the last element initHArray :: HArray ts -> HArray (Init ts) -- | Drop the first element tailHArray :: HArray ts -> HArray (Tail ts) newtype HArrayT m xs ys HArrayT :: (HArray xs -> m (HArray ys)) -> HArrayT m xs ys [runHArrayT] :: HArrayT m xs ys -> HArray xs -> m (HArray ys) -- | Compose HArrayT (>~:~>) :: Monad m => HArrayT m xs ys -> HArrayT m ys zs -> HArrayT m xs zs module Haskus.Utils.Maths -- | Return the GCD of a list of integrals -- --
-- >>> gcds [2,4,8] -- 2 --gcds :: Integral a => [a] -> a -- | Return the LCM of a list of integrals -- --
-- >>> lcms [2,3,5] -- 30 --lcms :: Integral a => [a] -> a -- | Monadic variable with cache module Haskus.Utils.MonadVar -- | A value that can be read with IO. The last read can be cached in it -- too. -- -- We store both the read value (type s) and a pure modifier function (s -- -> a). By doing this we can easily compare a read value to the -- cached one without performing extra computations. The functor instance -- compose with the modifier function. -- -- The supposedly costly modifier function is applied lazily data MonadVar m s a -- | IO accessor + modifier function MonadVar :: !m s -> (s -> a) -> MonadVar m s a -- | Additional cached transformed and read values. CachedMonadVar :: a -> !s -> !m s -> (s -> a) -> MonadVar m s a -- | Update an MonadVar without comparing to the cache even if it is -- available. -- -- Invariably produce an MonadVar with cached values. updateMonadVarForce :: (Monad m, Eq s) => MonadVar m s a -> m (MonadVar m s a) -- | Check if the MonadVar cache needs to be updated. -- -- Invariably produce an MonadVar with cached values or Nothing if the -- old one hasn't changed. updateMonadVarMaybe :: (Monad m, Eq s) => MonadVar m s a -> m (Maybe (MonadVar m s a)) -- | Check if the MonadVar cache needs to be updated. Return the updated -- MonadVar. -- -- Invariably produce an MonadVar with cached values. updateMonadVar :: (Monad m, Eq s) => MonadVar m s a -> m (MonadVar m s a) data MonadVarNE m s a -- | Additional cached transformed and read values. MonadVarNE :: a -> !Maybe s -> !m s -> (s -> a) -> MonadVarNE m s a -- | Check if the MonadVarNE cache needs to be updated. updateMonadVarNEMaybe :: (Monad m, Eq s) => MonadVarNE m s a -> m (Maybe (MonadVarNE m s a)) -- | Check if the MonadVarNE cache needs to be updated. Return the updated -- MonadVarNE updateMonadVarNE :: (Monad m, Eq s) => MonadVarNE m s a -> m (MonadVarNE m s a) instance GHC.Base.Functor (Haskus.Utils.MonadVar.MonadVarNE m s) instance GHC.Base.Functor (Haskus.Utils.MonadVar.MonadVar m s) -- | Monadic tree with cache module Haskus.Utils.MonadStream -- | Monadic stream with cache -- -- Both the structure and the values may be monadically dependent. The -- last monadic values read can be stored in a cache. data MonadStream m n a -- | Pure stream PureStream :: a -> n (MonadStream m n a) -> MonadStream m n a -- | Monadic stream MonadStream :: MonadVarNE m s (n (MonadStream m n a)) -> MonadStream m n a -- | Monadic rose tree type MonadTree m a = MonadStream m [] a -- | Monadic list type MonadList m a = MonadStream m Maybe a -- | Pretty-show an MonadStream showMonadStream :: (Foldable n, Show a, Eq (n (MonadStream m n a)), Monoid (n (MonadStream m n a))) => MonadStream m n a -> String -- | Pretty-show some MonadStreams showMonadStreams :: (Foldable n, Show a, Eq (n (MonadStream m n a)), Monoid (n (MonadStream m n a))) => n (MonadStream m n a) -> String -- | Update a MonadStream recursively. Reuse cached values when possible updateMonadStream :: (Monad m, Traversable n) => MonadStream m n a -> m (MonadStream m n a) -- | Update a MonadStream recursively. Reuse cached values when possible updateMonadStreamMaybe :: (Monad m, Traversable n) => MonadStream m n a -> m (Maybe (MonadStream m n a)) -- | Update a MonadStream forest recursively. Reuse cached values when -- possible updateMonadStreamsMaybe :: (Monad m, Traversable n) => n (MonadStream m n a) -> m (Maybe (n (MonadStream m n a))) -- | Update a MonadStream forest recursively updateMonadStreams :: (Monad m, Traversable n) => n (MonadStream m n a) -> m (n (MonadStream m n a)) instance GHC.Base.Functor n => GHC.Base.Functor (Haskus.Utils.MonadStream.MonadStream m n) -- | IO control-flow with cache module Haskus.Utils.MonadFlow -- | MonadFlow Functor data MonadFlowF m a e MonadEmit :: a -> e -> MonadFlowF m a e MonadRead :: m v -> (v -> e) -> MonadFlowF m a e MonadWith :: m v -> (v -> MonadFlow m a ()) -> e -> MonadFlowF m a e type MonadFlow m a r = Free (MonadFlowF m a) r -- | Run an MonadFlow runMonadFlow :: Monad m => MonadFlow m a r -> m (r, [a]) -- | Get a variable in IO -- -- Use withM to clearly limit the variable scope runM :: forall m v a. Eq v => m v -> MonadFlow m a v -- | Read and use an IO variable in a delimited scope withM :: Eq v => m v -> (v -> MonadFlow m a ()) -> MonadFlow m a () -- | Emit a pure value emitM :: a -> MonadFlow m a () -- | Cached control-flow data CachedMonadFlow m a CachedMonadFlow :: [MonadTree m a] -> (forall b. m b -> m b) -> CachedMonadFlow m a -- | Cached control-flow as an MonadTree [cachedTree] :: CachedMonadFlow m a -> [MonadTree m a] -- | Monadic context when performing an update (e.g. withSnapshot ctx) [cachedContext] :: CachedMonadFlow m a -> forall b. m b -> m b -- | Create a cache from an MonadFlow. -- -- Execute the MonadFlow once to get cached values cacheMonadFlow :: Monad m => (forall b. m b -> m b) -> MonadFlow m a r -> m (CachedMonadFlow m a) -- | Create a cache from an MonadFlow. -- -- This is the pure version: IO dependent nodes may not have any cached -- value cacheMonadFlowPure :: (forall b. m b -> m b) -> MonadFlow m a r -> CachedMonadFlow m a -- | Update a cached MonadFlow updateCachedMonadFlow :: Monad m => CachedMonadFlow m a -> m (CachedMonadFlow m a) -- | Update a cached MonadFlow updateCachedMonadFlowMaybe :: Monad m => CachedMonadFlow m a -> m (Maybe (CachedMonadFlow m a)) monadFlowToMonadTree :: MonadFlow m a r -> [MonadTree m a] instance GHC.Base.Functor (Haskus.Utils.MonadFlow.CachedMonadFlow m) instance GHC.Base.Functor (Haskus.Utils.MonadFlow.MonadFlowF m a) -- | State monad with multiple states (extensible) -- -- Similar to the multistate package, with the following differences (as -- of 0.7.0.0): * don't pollute Data.HList.HList * use HArray instead of -- a HList, for fast indexing module Haskus.Utils.MultiState -- | Multi-state monad transformer -- -- States are stacked in a heterogeneous array. type MStateT (s :: [*]) m a = StateT (HArray s) m a -- | Multi-state type MState (s :: [*]) a = MStateT s Identity a -- | Set a value in the state mSet :: (Monad m, HArrayIndexT a s) => a -> MStateT s m () -- | Get a value in the state mGet :: (Monad m, HArrayIndexT a s) => MStateT s m a -- | Try to get a value in the state mTryGet :: (Monad m, HArrayTryIndexT a s) => MStateT s m (Maybe a) -- | Modify a value in the state mModify :: (Monad m, HArrayIndexT a s) => (a -> a) -> MStateT s m () -- | Modify a value in the state (strict version) mModify' :: (Monad m, HArrayIndexT a s) => (a -> a) -> MStateT s m () -- | Execute an action with an extended state mWith :: forall s a m b. Monad m => a -> MStateT (a : s) m b -> MStateT s m b -- | Run MState runMState :: MState s a -> HArray s -> (a, HArray s) -- | Evaluate MState evalMState :: MState s a -> HArray s -> a -- | Execute MState execMState :: MState s a -> HArray s -> HArray s -- | Lift a multi-state into an HArray transformer liftMStateT :: Monad m => MStateT xs m x -> HArrayT m xs (x : xs) -- | Compose MStateT (>~:>) :: Monad m => HArrayT m xs ys -> MStateT ys m y -> HArrayT m xs (y : ys) -- | Compose MStateT (>:>) :: Monad m => MStateT xs m x -> MStateT (x : xs) m y -> HArrayT m xs (y : (x : xs)) -- | STM helpers module Haskus.Utils.STM -- | A monad supporting atomic memory transactions. data STM a -- | Retry execution of the current memory transaction because it has seen -- values in TVars which mean that it should not continue (e.g. -- the TVars represent a shared buffer that is now empty). The -- implementation may block the thread until one of the TVars that -- it has read from has been updated. (GHC only) retry :: () => STM a -- | Execute an STM transaction atomically atomically :: MonadIO m => STM a -> m a -- | Shared memory locations that support atomic memory transactions. data TVar a -- | Create a TVar newTVarIO :: MonadIO m => a -> m (TVar a) -- | Read a TVar in an IO monad readTVarIO :: MonadIO m => TVar a -> m a -- | Write the supplied value into a TVar. writeTVar :: () => TVar a -> a -> STM () -- | Write a TVar in an IO monad writeTVarIO :: MonadIO m => TVar a -> a -> m () -- | Return the current value stored in a TVar. readTVar :: () => TVar a -> STM a -- | Create a new TVar holding a value supplied newTVar :: () => a -> STM (TVar a) -- | Swap the contents of a TVar for a new value. swapTVar :: () => TVar a -> a -> STM a -- | Swap a TVar in an IO monad swapTVarIO :: MonadIO m => TVar a -> a -> m a -- | Mutate the contents of a TVar. N.B., this version is -- non-strict. modifyTVar :: () => TVar a -> (a -> a) -> STM () -- | Strict version of modifyTVar. modifyTVar' :: () => TVar a -> (a -> a) -> STM () -- | A TMVar is a synchronising variable, used for communication -- between concurrent threads. It can be thought of as a box, which may -- be empty or full. data TMVar a -- | Create a TMVar newTMVarIO :: MonadIO m => a -> m (TMVar a) -- | Check whether a given TMVar is empty. isEmptyTMVar :: () => TMVar a -> STM Bool -- | Create a TMVar which is initially empty. newEmptyTMVar :: () => STM (TMVar a) -- | IO version of newEmptyTMVar. This is useful for -- creating top-level TMVars using unsafePerformIO, because -- using atomically inside unsafePerformIO isn't possible. newEmptyTMVarIO :: () => IO (TMVar a) -- | This is a combination of takeTMVar and putTMVar; ie. it -- takes the value from the TMVar, puts it back, and also returns -- it. readTMVar :: () => TMVar a -> STM a -- | Return the contents of the TMVar. If the TMVar is -- currently empty, the transaction will retry. After a -- takeTMVar, the TMVar is left empty. takeTMVar :: () => TMVar a -> STM a -- | Put a value into a TMVar. If the TMVar is currently -- full, putTMVar will retry. putTMVar :: () => TMVar a -> a -> STM () -- | Swap the contents of a TMVar for a new value. swapTMVar :: () => TMVar a -> a -> STM a -- | A version of readTMVar which does not retry. Instead it returns -- Nothing if no value is available. tryReadTMVar :: () => TMVar a -> STM (Maybe a) -- | A version of putTMVar that does not retry. The -- tryPutTMVar function attempts to put the value a into -- the TMVar, returning True if it was successful, or -- False otherwise. tryPutTMVar :: () => TMVar a -> a -> STM Bool -- | A version of takeTMVar that does not retry. The -- tryTakeTMVar function returns Nothing if the -- TMVar was empty, or Just a if the TMVar -- was full with contents a. After tryTakeTMVar, the -- TMVar is left empty. tryTakeTMVar :: () => TMVar a -> STM (Maybe a) -- | TChan is an abstract type representing an unbounded FIFO -- channel. data TChan a -- | Create a broadcast channel newBroadcastTChanIO :: MonadIO m => m (TChan a) -- | Create a write-only TChan. More precisely, readTChan -- will retry even after items have been written to the channel. -- The only way to read a broadcast channel is to duplicate it with -- dupTChan. -- -- Consider a server that broadcasts messages to clients: -- --
-- serve :: TChan Message -> Client -> IO loop -- serve broadcastChan client = do -- myChan <- dupTChan broadcastChan -- forever $ do -- message <- readTChan myChan -- send client message ---- -- The problem with using newTChan to create the broadcast channel -- is that if it is only written to and never read, items will pile up in -- memory. By using newBroadcastTChan to create the broadcast -- channel, items can be garbage collected after clients have seen them. newBroadcastTChan :: () => STM (TChan a) -- | Write a value to a TChan. writeTChan :: () => TChan a -> a -> STM () -- | Duplicate a TChan: the duplicate channel begins empty, but data -- written to either channel from then on will be available from both. -- Hence this creates a kind of broadcast channel, where data written by -- anyone is seen by everyone else. dupTChan :: () => TChan a -> STM (TChan a) -- | Clone a TChan: similar to dupTChan, but the cloned channel -- starts with the same content available as the original channel. cloneTChan :: () => TChan a -> STM (TChan a) -- | Read the next value from the TChan. readTChan :: () => TChan a -> STM a -- | Future values (values that can only be set once) module Haskus.Utils.STM.Future -- | Future value of type a data Future a -- | Setter for a future value data FutureSource a -- | Create a Future and its source newFuture :: STM (Future a, FutureSource a) -- | newFuture in IO newFutureIO :: MonadIO m => m (Future a, FutureSource a) -- | Wait for a future waitFuture :: Future a -> STM a -- | Poll a future pollFuture :: Future a -> STM (Maybe a) -- | pollFuture in IO pollFutureIO :: MonadIO m => Future a -> m (Maybe a) -- | Set a future setFuture :: a -> FutureSource a -> STM () -- | Set a future in IO setFutureIO :: MonadIO m => a -> FutureSource a -> m () -- | Set a future -- -- Return False if it has already been set setFuture' :: a -> FutureSource a -> STM Bool -- | Snapshotable STM variables -- -- A SnapVar is like a TVar except that they have a context -- which can enable a snapshot mode. When in snapshot mode, the current -- values are not erased by writes. Instead each SnapVar can have 2 -- values: the value at the time of the snapshot and its current value. -- -- There can be only a single snapshot at a time. When the snapshot mode -- is exited, the variables only keep the current value alive, not the -- snapshot one. module Haskus.Utils.STM.SnapVar -- | A snapshot variable data SnapVar a -- | Snapshot context data SnapContext -- | Create a new snapshot context newSnapContextIO :: MonadIO m => m SnapContext -- | Create a new snapshot context newSnapContext :: STM SnapContext -- | Create a new SnapVar newSnapVarIO :: MonadIO m => SnapContext -> a -> m (SnapVar a) -- | Create a new SnapVar newSnapVar :: SnapContext -> a -> STM (SnapVar a) -- | Write a SnapVar writeSnapVar :: SnapVar a -> a -> STM () -- | Write a SnapVar writeSnapVarIO :: MonadIO m => SnapVar a -> a -> m () -- | Read a SnapVar readSnapVar :: SnapVar a -> STM a -- | Read a SnapVar readSnapVarIO :: MonadIO m => SnapVar a -> m a -- | Modify a SnapVar modifySnapVar :: SnapVar a -> (a -> a) -> STM a -- | Modify a SnapVar modifySnapVarIO :: MonadIO m => SnapVar a -> (a -> a) -> m a -- | Use a snapshot withSnapshot :: MonadIO m => SnapContext -> m r -> m r -- | Read the snapshot value of the variable. -- -- Must be used in the context of a withSnapshot readSnapshot :: SnapVar a -> STM a -- | Read the snapshot value of the variable. -- -- Must be used in the context of a withSnapshot readSnapshotIO :: MonadIO m => SnapVar a -> m a -- | Equality in a STM context module Haskus.Utils.STM.TEq class TEq a teq :: TEq a => a -> a -> STM Bool instance GHC.Classes.Eq a => Haskus.Utils.STM.TEq.TEq (GHC.Conc.Sync.TVar a) -- | Transactional list module Haskus.Utils.STM.TList -- | A double linked-list data TList a -- | A node in the list -- -- Every list has a marker node whose value is Nothing. Its nodePrev -- links to the last node and its nodeNext links to the first node. data TNode a -- | Empty node singleton empty :: STM (TList a) -- | Create a singleton list singleton :: e -> STM (TList e) -- | Indicate if the list is empty null :: TList e -> STM Bool -- | Count the number of elements in the list (0(n)) length :: TList e -> STM Word -- | Get the first element if any first :: TList e -> STM (Maybe (TNode e)) -- | Get the last element if any last :: TList e -> STM (Maybe (TNode e)) -- | Get the previous element if any prev :: TNode a -> STM (Maybe (TNode a)) -- | Get the next element if any next :: TNode a -> STM (Maybe (TNode a)) -- | Get value associated with a node value :: TNode a -> a -- | Remove all the elements of the list (O(1)) deleteAll :: TList a -> STM () -- | Delete a element of the list delete :: TNode a -> STM () -- | Only keep element matching the criterium filter :: (e -> STM Bool) -> TList e -> STM () -- | Find the first node matching the predicate (if any) find :: (e -> STM Bool) -> TList e -> STM (Maybe (TNode e)) -- | Append an element to the list append :: a -> TList a -> STM (TNode a) -- | Append an element to the list append_ :: a -> TList a -> STM () -- | Prepend an element to the list prepend :: a -> TList a -> STM (TNode a) -- | Prepend an element to the list prepend_ :: a -> TList a -> STM () -- | Insert an element before another insertBefore :: a -> TNode a -> STM (TNode a) -- | Insert an element after another insertAfter :: a -> TNode a -> STM (TNode a) -- | Convert into a list (O(n)) toList :: TList a -> STM [a] -- | Convert into a reversed list (O(n)) toReverseList :: TList a -> STM [a] -- | Create from a list fromList :: [e] -> STM (TList e) -- | Get the node from its index index :: Word -> TList e -> STM (Maybe (TNode e)) -- | Take (and remove) up to n elements in the list (O(n)) take :: Word -> TList e -> STM [e] -- | Transactionnal graph module Haskus.Utils.STM.TGraph -- | Deep-first graph traversal -- -- before is executed when the node is entered after is executed when the -- node is leaved children gets node's children deepFirst :: (Monad m, Ord a) => (a -> m ()) -> (a -> m ()) -> (a -> m [a]) -> [a] -> m () -- | Breadth-first graph traversal -- -- visit is executed when the node is entered. If False is returned, the -- traversal ends children gets node's children breadthFirst :: (Monad m, Ord a) => (a -> m Bool) -> (a -> m [a]) -> [a] -> m () -- | A node contains a value and two lists of incoming/outgoing edges data TNode a r TNode :: a -> TList (r, TNode a r) -> TList (r, TNode a r) -> TNode a r [nodeValue] :: TNode a r -> a [nodeEdgeIn] :: TNode a r -> TList (r, TNode a r) [nodeEdgeOut] :: TNode a r -> TList (r, TNode a r) -- | Create a graph node singleton :: a -> STM (TNode a r) -- | Link two nodes together linkTo :: TNode a r -> r -> TNode a r -> STM () -- | STm hashmap module Haskus.Utils.STM.TMap -- | STM hashmap type TMap a b = Map a b type Key a = (Eq a, Hashable a) -- | Indicate if the map is empty null :: TMap a b -> STM Bool -- | Get the number of elements in the map size :: TMap a b -> STM Int -- | Lookup an element in the map from its key lookup :: Key k => k -> TMap k a -> STM (Maybe a) -- | Check if a key is in the map member :: Key k => k -> TMap k b -> STM Bool -- | Check if a key is not in the map notMember :: Key k => k -> TMap k b -> STM Bool -- | Create an empty map empty :: STM (TMap a b) -- | Create a map containing a single element singleton :: Key k => k -> v -> STM (TMap k v) -- | Insert an element in the map insert :: Key k => k -> v -> TMap k v -> STM () -- | Create a new TMap from a list fromList :: Key k => [(k, v)] -> STM (TMap k v) -- | Delete an element from the map delete :: Key k => k -> TMap k v -> STM () -- | Get values elems :: TMap a b -> STM [b] -- | Get keys keys :: TMap a b -> STM [a] -- | Unsafe lookup in the map (!) :: Key k => TMap k v -> k -> STM v -- | STM mutable set module Haskus.Utils.STM.TSet -- | STM Set type TSet a = Set a type Element a = (Eq a, Hashable a) -- | Indicate if the set is empty null :: TSet a -> STM Bool -- | Number of elements in the set size :: TSet a -> STM Int -- | Check if an element is in the set member :: Element e => e -> TSet e -> STM Bool -- | Check if an element is not in the set notMember :: Element e => e -> TSet e -> STM Bool -- | Create an empty set empty :: STM (TSet e) -- | Create a set containing a single element singleton :: Element e => e -> STM (TSet e) -- | Insert an element in a set insert :: Element e => e -> TSet e -> STM () -- | Delete an element from a set delete :: Element e => e -> TSet e -> STM () -- | Convert a set into a list toList :: TSet e -> STM [e] -- | Create a set from a list fromList :: Element e => [e] -> STM (TSet e) -- | Get the set elements elems :: TSet e -> STM [e] -- | Get the set as a ListT stream stream :: TSet e -> ListT STM e -- | Perform a set union unions :: Element e => [TSet e] -> STM (TSet e) -- | Apply a function to each element in the set map :: Element b => (a -> b) -> TSet a -> STM (TSet b) -- | STM mutable tree module Haskus.Utils.STM.TTree -- | A STM mutable tree data TTree k v TTree :: k -> v -> TList (TTree k v) -> TVar (Maybe (TTree k v)) -> TTree k v -- | Node identifier [treeKey] :: TTree k v -> k -- | Node value [treeValue] :: TTree k v -> v -- | Children [treeChildren] :: TTree k v -> TList (TTree k v) -- | Parent [treeParent] :: TTree k v -> TVar (Maybe (TTree k v)) -- | Path in the tree newtype TTreePath k TTreePath :: [k] -> TTreePath k -- | Create a singleton node singleton :: k -> v -> STM (TTree k v) -- | Add a child addChild :: k -> v -> TTree k v -> STM (TTree k v) -- | Detach a child detachChild :: TEq k => TTree k v -> STM () -- | Attach a child a node (detaching it from a previous one if necessary) attachChild :: TEq k => TTree k v -> TTree k v -> STM () -- | Follow a path from a parent node treeFollowPath :: TEq k => TTree k v -> TTreePath k -> STM (Maybe (TTree k v)) -- | Simple Constraint solver module Haskus.Utils.Solver -- | Predicate state data PredState -- | Set predicate SetPred :: PredState -- | Unset predicate UnsetPred :: PredState -- | Undefined predicate UndefPred :: PredState -- | Invalid predicate (can't be used) InvalidPred :: PredState -- | Predicate oracle type PredOracle p = Map p PredState -- | Create an oracle from a list makeOracle :: Ord p => [(p, PredState)] -> PredOracle p -- | Get a list of valid and defined predicates from an oracle oraclePredicates :: Ord p => PredOracle p -> [(p, PredState)] -- | Oracle that always answer Undef emptyOracle :: PredOracle p -- | Combine two oracles TODO: check that there is no contradiction oracleUnion :: Ord p => PredOracle p -> PredOracle p -> PredOracle p -- | Ask an oracle if a predicate is set predIsSet :: Ord p => PredOracle p -> p -> Bool -- | Ask an oracle if a predicate is unset predIsUnset :: Ord p => PredOracle p -> p -> Bool -- | Ask an oracle if a predicate is undefined predIsUndef :: Ord p => PredOracle p -> p -> Bool -- | Ask an oracle if a predicate is invalid predIsInvalid :: Ord p => PredOracle p -> p -> Bool -- | Check the state of a predicate predIs :: Ord p => PredOracle p -> p -> PredState -> Bool -- | Get predicate state predState :: Ord p => PredOracle p -> p -> PredState -- | Add predicates to an oracle TODO: check that there is no contradiction predAdd :: Ord p => [(p, PredState)] -> PredOracle p -> PredOracle p -- | A constraint is a boolean expression -- -- p is the predicate type data Constraint e p -- | Predicate value Predicate :: p -> Constraint e p -- | Is the predicate valid IsValid :: p -> Constraint e p -- | Logic not Not :: Constraint e p -> Constraint e p -- | Logic and And :: [Constraint e p] -> Constraint e p -- | Logic or Or :: [Constraint e p] -> Constraint e p -- | Logic xor Xor :: [Constraint e p] -> Constraint e p -- | Constant CBool :: Bool -> Constraint e p -- | Error CErr :: Either String e -> Constraint e p -- | Optimize/simplify a constraint constraintOptimize :: Constraint e p -> Constraint e p -- | Reduce a constraint -- --
-- >>> data P = A | B deriving (Show,Eq,Ord) -- -- >>> let c = And [IsValid A, Predicate B] ---- --
-- >>> let oracle = makeOracle [(A,InvalidPred),(B,SetPred)] -- -- >>> constraintSimplify oracle c -- CBool False ---- --
-- >>> let oracle = makeOracle [(A,SetPred),(B,SetPred)] -- -- >>> constraintSimplify oracle c -- CBool True ---- --
-- >>> let oracle = makeOracle [(A,SetPred),(B,UnsetPred)] -- -- >>> constraintSimplify oracle c -- CBool False --constraintSimplify :: (Ord p, Eq p, Eq e) => PredOracle p -> Constraint e p -> Constraint e p -- | A rule can produce some "a"s (one or more if it diverges), depending -- on the constraints. data Rule e p a Terminal :: a -> Rule e p a OrderedNonTerminal :: [(Constraint e p, Rule e p a)] -> Rule e p a NonTerminal :: [(Constraint e p, Rule e p a)] -> Rule e p a Fail :: e -> Rule e p a -- | Simplify a rule given an oracle ruleSimplify :: (Ord p, Eq e) => PredOracle p -> Rule e p a -> Rule e p a -- | Constraint checking that a predicated value evaluates to some terminal evalsTo :: (Ord (Pred a), Eq a, Eq (PredTerm a), Eq (Pred a), Predicated a) => a -> PredTerm a -> Constraint e (Pred a) -- | Reduction result data MatchResult e nt t NoMatch :: MatchResult e nt t Match :: t -> MatchResult e nt t DontMatch :: nt -> MatchResult e nt t MatchFail :: [e] -> MatchResult e nt t MatchDiverge :: [nt] -> MatchResult e nt t -- | Predicated data -- --
-- data T
-- data NT
--
-- type family RuleT e p a s :: * where
-- RuleT e p a T = a
-- RuleT e p a NT = Rule e p a
--
-- data PD t = PD
-- { p1 :: RuleT () Bool Int t
-- , p2 :: RuleT () Bool String t
-- }
--
-- deriving instance Eq (PD T)
-- deriving instance Show (PD T)
-- deriving instance Ord (PD T)
-- deriving instance Eq (PD NT)
-- deriving instance Show (PD NT)
-- deriving instance Ord (PD NT)
--
--
-- instance Predicated (PD NT) where
-- type PredErr (PD NT) = ()
-- type Pred (PD NT) = Bool
-- type PredTerm (PD NT) = PD T
--
-- liftTerminal (PD a b) = PD (liftTerminal a) (liftTerminal b)
--
-- reducePredicates oracle (PD a b) =
-- initP PD PD
-- |> (applyP reducePredicates oracle a)
-- |> (applyP reducePredicates oracle b)
-- |> resultP
--
-- getTerminals (PD as bs) = [ PD a b | a <- getTerminals as
-- , b <- getTerminals bs
-- ]
--
-- getPredicates (PD a b) = concat
-- [ getPredicates a
-- , getPredicates b
-- ]
--
class (Ord (Pred a), Ord (PredTerm a)) => Predicated a where {
-- | Error type
type family PredErr a :: *;
-- | Predicate type
type family Pred a :: *;
-- | Terminal type
type family PredTerm a :: *;
}
-- | Build a non terminal from a terminal
liftTerminal :: Predicated a => PredTerm a -> a
-- | Reduce predicates
reducePredicates :: Predicated a => PredOracle (Pred a) -> a -> MatchResult (PredErr a) a (PredTerm a)
-- | Simplify predicates
simplifyPredicates :: Predicated a => PredOracle (Pred a) -> a -> a
-- | Get possible resulting terminals
getTerminals :: Predicated a => a -> Set (PredTerm a)
-- | Get used predicates
getPredicates :: Predicated a => a -> Set (Pred a)
-- | Create a table of predicates that return a terminal
createPredicateTable :: (Ord (Pred a), Eq (Pred a), Eq a, Predicated a, Predicated a, Pred a ~ Pred a) => a -> (PredOracle (Pred a) -> Bool) -> Either (PredTerm a) [(PredOracle (Pred a), PredTerm a)]
-- | Initialise a reduction result (typically with two
-- functions/constructors)
initP :: nt -> t -> MatchResult e nt (nt, t)
-- | Compose reduction results
--
-- We reuse the MatchResult data type: * a "terminal" on the left can be
-- used to build either a terminal or a non terminal * a "non terminal"
-- on the left can only be used to build a non terminal
applyP :: Predicated ntb => MatchResult e (ntb -> nt) (ntb -> nt, PredTerm ntb -> t) -> MatchResult e ntb (PredTerm ntb) -> MatchResult e nt (nt, t)
-- | Fixup result (see initP and applyP)
resultP :: MatchResult e nt (nt, t) -> MatchResult e nt t
instance (GHC.Classes.Ord t, GHC.Classes.Ord nt, GHC.Classes.Ord e) => GHC.Classes.Ord (Haskus.Utils.Solver.MatchResult e nt t)
instance (GHC.Classes.Eq t, GHC.Classes.Eq nt, GHC.Classes.Eq e) => GHC.Classes.Eq (Haskus.Utils.Solver.MatchResult e nt t)
instance (GHC.Show.Show t, GHC.Show.Show nt, GHC.Show.Show e) => GHC.Show.Show (Haskus.Utils.Solver.MatchResult e nt t)
instance (GHC.Classes.Ord a, GHC.Classes.Ord p, GHC.Classes.Ord e) => GHC.Classes.Ord (Haskus.Utils.Solver.Rule e p a)
instance (GHC.Classes.Eq a, GHC.Classes.Eq p, GHC.Classes.Eq e) => GHC.Classes.Eq (Haskus.Utils.Solver.Rule e p a)
instance (GHC.Show.Show a, GHC.Show.Show p, GHC.Show.Show e) => GHC.Show.Show (Haskus.Utils.Solver.Rule e p a)
instance (GHC.Classes.Ord p, GHC.Classes.Ord e) => GHC.Classes.Ord (Haskus.Utils.Solver.Constraint e p)
instance (GHC.Classes.Eq p, GHC.Classes.Eq e) => GHC.Classes.Eq (Haskus.Utils.Solver.Constraint e p)
instance (GHC.Show.Show p, GHC.Show.Show e) => GHC.Show.Show (Haskus.Utils.Solver.Constraint e p)
instance GHC.Classes.Ord Haskus.Utils.Solver.PredState
instance GHC.Classes.Eq Haskus.Utils.Solver.PredState
instance GHC.Show.Show Haskus.Utils.Solver.PredState
instance (GHC.Classes.Ord a, GHC.Classes.Ord p, GHC.Classes.Eq e, GHC.Classes.Eq a, GHC.Classes.Eq p) => Haskus.Utils.Solver.Predicated (Haskus.Utils.Solver.Rule e p a)
instance (GHC.Classes.Ord p, GHC.Classes.Eq e, GHC.Classes.Eq p) => Haskus.Utils.Solver.Predicated (Haskus.Utils.Solver.Constraint e p)
instance (Haskus.Utils.Solver.Predicated x, Haskus.Utils.Solver.Predicated y, Haskus.Utils.Solver.PredErr x Data.Type.Equality.~ Haskus.Utils.Solver.PredErr y, Haskus.Utils.Solver.Pred x Data.Type.Equality.~ Haskus.Utils.Solver.Pred y) => Haskus.Utils.Solver.Predicated (x, y)
instance GHC.Base.Functor (Haskus.Utils.Solver.MatchResult e nt)
instance GHC.Base.Functor (Haskus.Utils.Solver.Rule e p)
instance GHC.Base.Functor (Haskus.Utils.Solver.Constraint e)
-- | Mutable value with associated last write time
module Haskus.Utils.TimedValue
-- | Value with Eq/Ord instances uniquely based on time field indicating
-- the time the value was last written.
--
-- This can be used with IOVar/IOTree which use Eq instances to detect
-- value changes. It can be useful for values that we don't want to
-- structurally compare (because it is too costly or because we can't)
--
-- t should be SystemTime (fast to query monotonic clock)
data TimedValue t a
TimedValue :: t -> a -> TimedValue t a
instance GHC.Classes.Eq t => GHC.Classes.Eq (Haskus.Utils.TimedValue.TimedValue t a)
instance GHC.Classes.Ord t => GHC.Classes.Ord (Haskus.Utils.TimedValue.TimedValue t a)