| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Data.Stream
Synopsis
- data StreamT (m :: Type -> Type) a = StreamT {}
- unfold :: forall (m :: Type -> Type) s a. Applicative m => s -> (s -> Result s a) -> StreamT m a
- unfold_ :: forall (m :: Type -> Type) s. Applicative m => s -> (s -> s) -> StreamT m s
- constM :: Functor m => m a -> StreamT m a
- mmap :: Monad m => (a -> m b) -> StreamT m a -> StreamT m b
- toRecursive :: forall (m :: Type -> Type) a. Functor m => StreamT m a -> Recursive m a
- fromRecursive :: forall (m :: Type -> Type) a. Recursive m a -> StreamT m a
- initialised :: Monad m => m a -> StreamT m a
- hoist' :: (forall x. m1 x -> m2 x) -> StreamT m1 a -> StreamT m2 a
- stepStream :: Functor m => StreamT m a -> m (Result (StreamT m a) a)
- reactimate :: Monad m => StreamT m () -> m void
- streamToList :: Monad m => StreamT m a -> m [a]
- withStreamT :: (Functor m, Functor n) => (forall s. m (Result s a) -> n (Result s b)) -> StreamT m a -> StreamT n b
- concatS :: forall (m :: Type -> Type) a. Monad m => StreamT m [a] -> StreamT m a
- snapshot :: Functor m => StreamT m a -> StreamT m (m a)
- applyExcept :: forall (m :: Type -> Type) e1 e2 a. Monad m => StreamT (ExceptT (e1 -> e2) m) a -> StreamT (ExceptT e1 m) a -> StreamT (ExceptT e2 m) a
- foreverExcept :: forall (m :: Type -> Type) e a. (Functor m, Monad m) => StreamT (ExceptT e m) a -> StreamT m a
- exceptS :: forall (m :: Type -> Type) e b. Applicative m => StreamT (ExceptT e m) b -> StreamT m (Either e b)
- selectExcept :: forall (m :: Type -> Type) e1 e2 a. Monad m => StreamT (ExceptT (Either e1 e2) m) a -> StreamT (ExceptT (e1 -> e2) m) a -> StreamT (ExceptT e2 m) a
- fixStream :: Functor m => (forall s. s -> t s) -> (forall s. (s -> m (Result s a)) -> t s -> m (Result (t s) a)) -> StreamT m a
- fixStream' :: Functor m => (forall s. s -> t s) -> (forall s. s -> (s -> m (Result s a)) -> t s -> m (Result (t s) a)) -> StreamT m a
- fixA :: forall (m :: Type -> Type) a. Applicative m => StreamT m (a -> a) -> StreamT m a
- liftS :: forall (m :: Type -> Type) (t :: (Type -> Type) -> Type -> Type) a. (Monad m, MonadTrans t) => StreamT m a -> StreamT (t m) a
- handleEffect :: (Monad m, Monad eff, Functor sig) => (forall x. sig x -> eff x) -> (forall x. eff x -> m (sig x)) -> StreamT eff a -> StreamT m (sig a)
- handleExceptT :: forall (m :: Type -> Type) e a. Monad m => StreamT (ExceptT e m) a -> StreamT m (Either e a)
- handleWriterT :: forall (m :: Type -> Type) w a. (Monad m, Monoid w) => StreamT (WriterT w m) a -> StreamT m (w, a)
- handleMaybeT :: forall (m :: Type -> Type) a. Monad m => StreamT (MaybeT m) a -> StreamT m (Maybe a)
Creating streams
data StreamT (m :: Type -> Type) a Source #
Effectful streams in coalgebraic encoding.
A stream consists of an internal state s, and a step function.
This step can make use of an effect in m (which is often a monad),
alter the state, and return a result value.
Its semantics is continuously outputting values of type b,
while performing side effects in m.
A coalgebraic encoding was chosen instead of the direct recursion known from e.g. list-transformer, dunai, machines, streaming, ...,
because the coalgebraic encoding is much more amenable to compiler optimizations
than the coalgebraic encoding, which is:
data StreamRecursiveT m b = StreamRecursiveT (m (b, StreamRecursiveT m b))
When two streams are composed, GHC can often optimize the combined step function, resulting in a faster streams than what the coalgebraic encoding can ever achieve, because the coalgebraic encoding has to step through every continuation. Put differently, the compiler can perform static analysis on the state types of initially encoded state machines, while the coalgebraic encoding knows its state only at runtime.
This performance gain comes at a peculiar cost:
Recursive definitions of streams are not possible, e.g. an equation like:
fixA stream = stream * fixA stream
This is impossible since the stream under definition itself appears in the definition body,
and thus the internal state type would be recursively defined, which GHC doesn't allow:
Type level recursion is not supported in existential types.
An stream defined thusly will typically hang and/or leak memory, trying to build up an infinite type at runtime.
It is nevertheless possible to define streams recursively, but one needs to first identify the recursive definition of its state type.
Then for the greatest generality, fixStream and fixStream' can be used, and some special cases are covered by functions
such as fixA, parallely, many and some.
Constructors
| StreamT | |
Instances
| MFunctor StreamT Source # | |
| Foldable m => Foldable (StreamT m) Source # | |
Defined in Data.Stream Methods fold :: Monoid m0 => StreamT m m0 -> m0 # foldMap :: Monoid m0 => (a -> m0) -> StreamT m a -> m0 # foldMap' :: Monoid m0 => (a -> m0) -> StreamT m a -> m0 # foldr :: (a -> b -> b) -> b -> StreamT m a -> b # foldr' :: (a -> b -> b) -> b -> StreamT m a -> b # foldl :: (b -> a -> b) -> b -> StreamT m a -> b # foldl' :: (b -> a -> b) -> b -> StreamT m a -> b # foldr1 :: (a -> a -> a) -> StreamT m a -> a # foldl1 :: (a -> a -> a) -> StreamT m a -> a # toList :: StreamT m a -> [a] # length :: StreamT m a -> Int # elem :: Eq a => a -> StreamT m a -> Bool # maximum :: Ord a => StreamT m a -> a # minimum :: Ord a => StreamT m a -> a # | |
| (Traversable m, Functor m) => Traversable (StreamT m) Source # | |
Defined in Data.Stream | |
| Alternative m => Alternative (StreamT m) Source # |
|
| Applicative m => Applicative (StreamT m) Source # |
|
| Functor m => Functor (StreamT m) Source # | |
| Selective m => Selective (StreamT m) Source # | |
| Align m => Align (StreamT m) Source # | |
Defined in Data.Stream | |
| Semialign m => Semialign (StreamT m) Source # | Run both streams in parallel and use |
| (Applicative m, Floating a) => Floating (StreamT m a) Source # | |
Defined in Data.Stream Methods exp :: StreamT m a -> StreamT m a # log :: StreamT m a -> StreamT m a # sqrt :: StreamT m a -> StreamT m a # (**) :: StreamT m a -> StreamT m a -> StreamT m a # logBase :: StreamT m a -> StreamT m a -> StreamT m a # sin :: StreamT m a -> StreamT m a # cos :: StreamT m a -> StreamT m a # tan :: StreamT m a -> StreamT m a # asin :: StreamT m a -> StreamT m a # acos :: StreamT m a -> StreamT m a # atan :: StreamT m a -> StreamT m a # sinh :: StreamT m a -> StreamT m a # cosh :: StreamT m a -> StreamT m a # tanh :: StreamT m a -> StreamT m a # asinh :: StreamT m a -> StreamT m a # acosh :: StreamT m a -> StreamT m a # atanh :: StreamT m a -> StreamT m a # log1p :: StreamT m a -> StreamT m a # expm1 :: StreamT m a -> StreamT m a # | |
| (Applicative m, Num a) => Num (StreamT m a) Source # | |
Defined in Data.Stream Methods (+) :: StreamT m a -> StreamT m a -> StreamT m a # (-) :: StreamT m a -> StreamT m a -> StreamT m a # (*) :: StreamT m a -> StreamT m a -> StreamT m a # negate :: StreamT m a -> StreamT m a # abs :: StreamT m a -> StreamT m a # signum :: StreamT m a -> StreamT m a # fromInteger :: Integer -> StreamT m a # | |
| (Applicative m, Fractional a) => Fractional (StreamT m a) Source # | |
| (VectorSpace v s, Eq s, Floating s, Applicative m) => VectorSpace (StreamT m v) (StreamT m s) Source # | |
Defined in Data.Stream Methods zeroVector :: StreamT m v # (*^) :: StreamT m s -> StreamT m v -> StreamT m v # (^/) :: StreamT m v -> StreamT m s -> StreamT m v # (^+^) :: StreamT m v -> StreamT m v -> StreamT m v # (^-^) :: StreamT m v -> StreamT m v -> StreamT m v # negateVector :: StreamT m v -> StreamT m v # dot :: StreamT m v -> StreamT m v -> StreamT m s # | |
unfold :: forall (m :: Type -> Type) s a. Applicative m => s -> (s -> Result s a) -> StreamT m a Source #
Initialise with an internal state, update the state and produce output without side effects.
unfold_ :: forall (m :: Type -> Type) s. Applicative m => s -> (s -> s) -> StreamT m s Source #
Like unfold, but output the current state.
constM :: Functor m => m a -> StreamT m a Source #
Constantly perform the same effect, without remembering a state.
mmap :: Monad m => (a -> m b) -> StreamT m a -> StreamT m b Source #
Like fmap or rmap, but the postcomposed function may have an effect in m.
toRecursive :: forall (m :: Type -> Type) a. Functor m => StreamT m a -> Recursive m a Source #
Translate a coalgebraically encoded stream into a recursive one.
This is usually a performance penalty.
fromRecursive :: forall (m :: Type -> Type) a. Recursive m a -> StreamT m a Source #
Translate a recursive stream into a coalgebraically encoded one.
The internal state is the stream itself.
initialised :: Monad m => m a -> StreamT m a Source #
Call the monadic action once on the first tick and provide its result indefinitely.
Running streams
stepStream :: Functor m => StreamT m a -> m (Result (StreamT m a) a) Source #
Perform one step of a stream, resulting in an updated stream and an output value.
reactimate :: Monad m => StreamT m () -> m void Source #
Run a stream with trivial output.
If the output of a stream does not contain information,
all of its meaning is in its effects.
This function runs the stream indefinitely.
Since it will never return with a value, this function also has no output (its output is void).
The only way it can return is if m includes some effect of termination,
e.g. Maybe or Either could terminate with a Nothing or Left value,
or IO can raise an exception.
streamToList :: Monad m => StreamT m a -> m [a] Source #
Run a stream, collecting the outputs in a lazy, infinite list.
Modifying streams
withStreamT :: (Functor m, Functor n) => (forall s. m (Result s a) -> n (Result s b)) -> StreamT m a -> StreamT n b Source #
Change the output type and effect of a stream without changing its state type.
concatS :: forall (m :: Type -> Type) a. Monad m => StreamT m [a] -> StreamT m a Source #
Buffer the output of a stream, returning one value at a time.
This function lets a stream control the speed at which it produces data, since it can decide to produce any amount of output at every step.
snapshot :: Functor m => StreamT m a -> StreamT m (m a) Source #
At each step, duplicate the m effect of the current step to the output.
This is useful if m has some means of static analysis, or if you want to re-perform the effects.
Exception handling
applyExcept :: forall (m :: Type -> Type) e1 e2 a. Monad m => StreamT (ExceptT (e1 -> e2) m) a -> StreamT (ExceptT e1 m) a -> StreamT (ExceptT e2 m) a Source #
Streams with exceptions are Applicative in the exception type.
Run the first stream until it throws a function as an exception, then run the second one. If the second one ever throws an exception, apply the function thrown by the first one to it.
foreverExcept :: forall (m :: Type -> Type) e a. (Functor m, Monad m) => StreamT (ExceptT e m) a -> StreamT m a Source #
Execute the stream until it throws an exception, then restart it.
One might be tempted to define this function recursively with applyExcept,
but this would result in a runtime error, trying to define an infinite state.
exceptS :: forall (m :: Type -> Type) e b. Applicative m => StreamT (ExceptT e m) b -> StreamT m (Either e b) Source #
Whenever an exception occurs, output it and retry on the next step.
selectExcept :: forall (m :: Type -> Type) e1 e2 a. Monad m => StreamT (ExceptT (Either e1 e2) m) a -> StreamT (ExceptT (e1 -> e2) m) a -> StreamT (ExceptT e2 m) a Source #
Fix points, or recursive definitions
Arguments
| :: Functor m | |
| => (forall s. s -> t s) | The recursive definition of the state of the stream. |
| -> (forall s. (s -> m (Result s a)) -> t s -> m (Result (t s) a)) | The recursive definition of the step function of the stream. |
| -> StreamT m a |
Recursively define a stream from a recursive definition of the state, and of the step function.
If you want to define a stream recursively, this is not possible directly.
For example, consider this definition:
loops :: Monad m => StreamT m [Int]
loops = (:) $ unfold_ 0 (+ 1) * loops
The defined value loops contains itself in its definition.
This means that the internal state type of loops must itself be recursively defined.
But GHC cannot do this automatically, because type level and value level are separate.
Instead, we need to spell out the type level recursion explicitly with a type constructor,
over which we will take the fixpoint.
In this example, we can figure out from the definitions that:
1. has unfold_ 0 (+ 1)0 :: Int as state
2. (:) does not change the state
3. <*> takes the product of both states
So the internal state s of loops must satisfy the equation s = (Int, s).
If the recursion is written as above, it tries to compute the infinite tuple (Int, (Int, (Int, ...))), which hangs.
Instead, we need to define a type operator over which we take the fixpoint:
-- You need to write this: data Loops x = Loops Int x -- The library supplies: data Fix f = Fix f (Fix f) type LoopsState = Fix Loops
We can then use fixStream to define the recursive definition of loops.
For this, we have to to tediously inline the definitions of unfold_, (:), and <*>,
until we arrive at an explicit recursive definition of the state and the step function of loops, separately.
These are the two arguments of fixStream.
loops :: Monad m => StreamT m [Int] loops = fixStream (Loops 0) $ fixStep (Loops n fixState) -> do Result s' a <- fixStep fixState return $ Result (Loops (n + 1) s') a
Arguments
| :: Functor m | |
| => (forall s. s -> t s) | |
| -> (forall s. s -> (s -> m (Result s a)) -> t s -> m (Result (t s) a)) | The recursive definition of the state of the stream. |
| -> StreamT m a | The recursive definition of the step function of the stream. |
A generalisation of fixStream where the step definition is allowed to depend on the state.
Effect handling
liftS :: forall (m :: Type -> Type) (t :: (Type -> Type) -> Type -> Type) a. (Monad m, MonadTrans t) => StreamT m a -> StreamT (t m) a Source #
Lift the monad of a stream into a transformer.
Arguments
| :: (Monad m, Monad eff, Functor sig) | |
| => (forall x. sig x -> eff x) | Send a declarative effect in the signature to the effect carrier monad. |
| -> (forall x. eff x -> m (sig x)) | Interpret the effect in |
| -> StreamT eff a | |
| -> StreamT m (sig a) |
Continuously interpret a first order effect.
Several types are relevant here:
sig: An effect signature functor, that encodes one effect. For example,for raising exceptions of typeEitheree, or(w, )for a logging effect.eff: A monad that carries the effect. This can be a monad transformer stack including a transformer corresponding tosig, such asExceptTforEither. It can also be theEffmonad of an effect library such aspolysemy,bluefin,effectfuland so on.m: The underlying monad in which the interpretation is performed, think "effwithout the effects fromsig".
This function takes two functions, one to create effects in eff from the signature, and the other to fully interpret them in m,
storing the complete effect information in sig again.
It then executes the given automaton, extracting the effect by interpretation, and sending it back in.
The execution semantics is that of the monad eff, while the pure effect of the whole computation is returned in the output, encoded in sig.
For examples, see handleExceptT, handleWriterT and similar functions below.
handleExceptT :: forall (m :: Type -> Type) e a. Monad m => StreamT (ExceptT e m) a -> StreamT m (Either e a) Source #
Execute a stream until it throws an exception, then output the exception forever.