overeasy-0.1.0: src/Overeasy/Streams.hs
-- | Stuff for streaming search results.
module Overeasy.Streams
( chooseWith
, choose
, Stream
, streamAll
) where
import Control.Applicative (Alternative (..))
import Control.Monad (MonadPlus)
import Control.Monad.Logic (LogicT, MonadLogic, observeAllT)
import Control.Monad.Reader (MonadReader (..), ReaderT (..))
import Control.Monad.State.Strict (MonadState (..), State, runState)
newtype M r s a = M { unM :: ReaderT r (State s) a }
deriving newtype (
Functor, Applicative, Monad,
MonadReader r, MonadState s)
runM :: M r s a -> r -> s -> (a, s)
runM m r = runState (runReaderT (unM m) r)
-- | Choose one of many alteratives and process it with the given function.
chooseWith :: (Foldable f, Alternative m) => f a -> (a -> m b) -> m b
chooseWith fa f = foldr ((<|>) . f) empty fa
-- | Choose one of many alteratives.
choose :: (Foldable f, Alternative m) => f a -> m a
choose fa = chooseWith fa pure
-- | A stream of results. Just a wrapper around 'LogicT' to keep things tidy.
newtype Stream r s a = Stream { unStream :: LogicT (M r s) a }
deriving newtype (
Functor, Applicative, Monad,
MonadReader r, MonadState s, MonadLogic,
Alternative, MonadPlus, Semigroup, Monoid)
-- | Produces all results from the stream.
streamAll :: Stream r s a -> r -> s -> [a]
streamAll stream env st = fst (runM (observeAllT (unStream stream)) env st)