packages feed

auto 0.4.1.0 → 0.4.2.0

raw patch · 9 files changed

+320/−42 lines, 9 filesdep ~MonadRandomdep ~basedep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: MonadRandom, base, bytestring, cereal, containers, deepseq, profunctors, random, semigroups, transformers

API changes (from Hackage documentation)

+ Control.Auto.Blip: asMaybes :: Auto m (Blip a) (Maybe a)
+ Control.Auto.Blip: collectB :: (Serialize a, Serialize b) => Auto m (Blip a, Blip b) (Blip (a, b))
+ Control.Auto.Blip: collectB_ :: Auto m (Blip a, Blip b) (Blip (a, b))
+ Control.Auto.Blip: collectBs :: Serialize a => Int -> Auto m (Blip a) (Blip [a])
+ Control.Auto.Blip: collectBs_ :: Int -> Auto m (Blip a) (Blip [a])
+ Control.Auto.Blip: collectN :: Serialize a => Int -> Auto m a (Blip [a])
+ Control.Auto.Blip: collectN_ :: Int -> Auto m a (Blip [a])
+ Control.Auto.Blip: emitEithers :: (a -> Either b c) -> Auto m a (Blip b, Blip c)
+ Control.Auto.Blip: onEithers :: Auto m (Either a b) (Blip a, Blip b)
+ Control.Auto.Blip: substituteB :: Auto m (a, Blip a) a
+ Control.Auto.Collection: muxI :: (Serialize k, Ord k, Monad m) => (k -> Interval m a b) -> Auto m (k, a) (Maybe b)
+ Control.Auto.Collection: muxI_ :: (Ord k, Monad m) => (k -> Interval m a b) -> Auto m (k, a) (Maybe b)
+ Control.Auto.Collection: muxManyI :: (Serialize k, Ord k, Monad m) => (k -> Interval m a b) -> Auto m (Map k a) (Map k b)
+ Control.Auto.Collection: muxManyI_ :: (Ord k, Monad m) => (k -> Interval m a b) -> Auto m (Map k a) (Map k b)
+ Control.Auto.Switch: switchIn :: Monad m => Int -> Auto m a b -> Auto m a b -> Auto m a b

Files

CHANGELOG.md view
@@ -1,3 +1,40 @@+0.4.2.0+-------+<https://github.com/mstksg/auto/releases/tag/v0.4.2.0>++*   Removed all upper bounds on dependencies.+*   **Control.Auto.Blip**: Companions to `emitJusts` and `onJusts` added, for+    `Either`: `emitEithers` and `onEithers`.  Emit every item inputted, but+    fork them into one of two output blit streams based on `Right` or `Left`+    properties.  Only preserves blip semantics/makes sense if any given+    input's `Right` or `Left`ness is expected to be independent from the last+    received one.+*   **Control.Auto.Blip**: New "blip stream collapsers", `asMaybes` and+    `substituteB`.  `asMaybes` turns a blip stream into a stream of `Maybe`s,+    `Just` when something was emitted, and `Nothing` when not.  `substituteB`+    takes a regular stream and a blip stream, and outputs the values of the+    regular stream whenever the blip stream doesn't emit and the emitted value+    when it does --- basically a more powerful version of `fromBlips`, where+    the "default" value now comes from a stream instead of being always the+    same.+*   **Control.Auto.Blip**: New blip stream creator, `collectN`, which emits+    every `n` steps with the last `n` items received.+*   **Control.Auto.Blip**: New blip stream modifiers, `collectB` and+    `collectBs`.   `collectB` waits on two blip streams and emits after it has+    received something from *both*.  `collectBs` is like `collectN`, except+    emits after every `n` emitted values received with the past `n` emitted+    values.+*   **Control.Auto.Collection**: "Intervaled" counterparts to `mux` and+    `muxMany`, `muxI` and `muxManyI`.  They store `Interval`s instead of+    `Auto`s...and when the `Interval`s turned "off", they are removed from the+    collection.+*   **Control.Auto.Switch**: A new "count-down" swithcer, `switchIn`, which+    acts a bit like `(-->)` and `(-?>)`, except the switch happens+    deterministically after a pre-set given number of steps.  Act like the+    first `Auto` for a given number of steps, and then act like the second+    ever after.  Basically a direct implementation of the common+    `onFor n a1 --> a2` idiom.+ 0.4.1.0 ------- <https://github.com/mstksg/auto/releases/tag/v0.4.1.0>@@ -5,10 +42,10 @@ *   Adapted to more consistent semantic versioning scheme, where the third     number is a new update, and the fourth number is reserved for bug fixes. *   **Control.Auto.Blip**: `foldrB` and `foldlB'` officially **deprecated** in-    their current forms.  From `0.5`, they will have corrected functionality-    and a new type signature.  The current functionality doesn't really make-    sense, and was a mistake during their implementation.  You can begin using-    the new versions now, with:+    their current forms.  From version `0.5`, they will have corrected+    functionality and a new type signature.  The current functionality doesn't+    really make sense, and was a mistake during their implementation.  You can+    begin using the new versions now, with:      ```     foldrB  = foldr  (merge f) mempty
auto.cabal view
@@ -1,5 +1,5 @@ name:                auto-version:             0.4.1.0+version:             0.4.2.0 synopsis:            Denotative, locally stateful programming DSL & platform description:         (Up to date documentation is maintained at                      <https://mstksg.github.com/auto>)@@ -41,7 +41,7 @@                      repository on github for plenty of real-world and toy                      examples to learn from; I've also done a                      <blog.jle.im/entries/series/+all-about-auto blog series>-                     on this library, for examples and full tutorials!+                     on this library, with examples and full tutorials!                      .                      Support available on freenode's #haskell-auto,                      #haskell-game, and also on the github issue@@ -85,16 +85,16 @@                      , Control.Auto.Time   -- other-modules:   -- other-extensions:-  build-depends:       base         >= 4.6      && < 4.9-                     , MonadRandom  >= 0.3.0.1  && < 0.4-                     , bytestring   >= 0.10.4.0 && < 0.11-                     , cereal       >= 0.4.1.1  && < 0.5-                     , containers   >= 0.5.5.1  && < 0.6-                     , deepseq      >= 1.3.0.2  && < 2.0-                     , profunctors  >= 4.3      && < 5.0-                     , random       >= 1.1      && < 2.0-                     , semigroups   >= 0.16     && < 0.17-                     , transformers >= 0.4.2.0  && < 0.5+  build-depends:       base         >= 4.6      && < 5+                     , MonadRandom  >= 0.3.0.1+                     , bytestring   >= 0.10.4.0+                     , cereal       >= 0.4.1.1+                     , containers   >= 0.5.5.1+                     , deepseq      >= 1.3.0.2+                     , profunctors  >= 4.3+                     , random       >= 1.1+                     , semigroups   >= 0.16+                     , transformers >= 0.4.2.0   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:         -Wall
src/Control/Auto/Blip.hs view
@@ -31,15 +31,19 @@   , mergeRs   , foldrB   , foldlB'-  -- ** Blip stream creation (dangerous!)+  -- ** "Raw" blip stream creation (dangerous!)   , emitJusts-  , emitOn+  , emitEithers   , onJusts+  , onEithers+  , emitOn   -- ** Blip stream collapse   , fromBlips   , fromBlipsWith+  , asMaybes   , holdWith   , holdWith_+  , substituteB   -- * Step/"time" based Blip streams and generators   , never   , immediately@@ -47,6 +51,8 @@   , every   , eachAt   , eachAt_+  , collectN+  , collectN_   -- * Modifying Blip streams   , tagBlips   , modifyBlips@@ -58,6 +64,10 @@   , lagBlips_   , filterB   , splitB+  , collectB+  , collectB_+  , collectBs+  , collectBs_   , joinB   , mapMaybeB   , takeB@@ -293,6 +303,9 @@ -- foldrB :: (a -> a -> a) -> a -> [Blip a] -> Blip a foldrB f x0 = foldr (merge f) (Blip x0)+{-# DEPRECATED foldrB "Starting in v0.5, will have new functionality." #-}++ -- foldrB :: (a -> a -> a) -> [Blip a] -> Blip a -- foldrB f = foldr (merge f) NoBlip @@ -319,6 +332,8 @@ -- @ foldlB' :: (a -> a -> a) -> a -> [Blip a] -> Blip a foldlB' f x0 = foldl' (merge f) (Blip x0)+{-# DEPRECATED foldlB' "Starting in v0.5, will have new functionality." #-}+ -- foldlB' :: (a -> a -> a) -> [Blip a] -> Blip a -- foldlB' f = foldl' (merge f) NoBlip @@ -386,6 +401,38 @@     f x (Just i) | i <= 1    = (Blip x, Nothing)                  | otherwise = (NoBlip, Just (i - 1)) +-- | @'collectN' n@ emits every @n@ steps, emitting with the @n@ last items+-- received.+--+-- >>> streamAuto' (collectN 3) [1..10]+-- [ NoBlip, NoBlip, Blip [1,2,3], NoBlip, NoBlip, Blip [4,5,6]+-- , NoBlip, NoBlip, Blip [7,8,9], NoBlip ]+--+collectN :: Serialize a => Int -> Auto m a (Blip [a])+collectN (max 1 -> n) = mkState (_collectBsF n . Blip) (n, [])++-- | The non-serializing/non-resuming version of 'collectN'+collectN_ :: Int -> Auto m a (Blip [a])+collectN_ (max 1 -> n) = mkState_ (_collectBsF n . Blip) (n, [])++-- | A blip stream that listens to an input blip stream and emits after the+-- input stream emits a given number of times.  Emits with a list of all+-- received emitted values.+collectBs :: Serialize a => Int -> Auto m (Blip a) (Blip [a])+collectBs (max 1 -> n) = mkState (_collectBsF n) (n, [])++-- | The non-serializing/non-resuming version of 'collectBs'.+collectBs_ :: Int -> Auto m (Blip a) (Blip [a])+collectBs_ (max 1 -> n) = mkState_ (_collectBsF n) (n, [])++-- n expected to be strictly positive+_collectBsF :: Int -> Blip a -> (Int, [a]) -> (Blip [a], (Int, [a]))+_collectBsF n = f+  where+    f (Blip x) (i, xs) | i == 1    = (Blip (reverse (x:xs)), (n    , []  ))+                       | otherwise = (NoBlip               , (i - 1, x:xs))+    f _        s       = (NoBlip, s)+ -- | Produces a blip stream that emits the input value whenever the input -- satisfies a given predicate. --@@ -507,6 +554,34 @@ joinB :: Auto m (Blip (Blip a)) (Blip a) joinB = mkFunc (blip NoBlip id) +-- | Waits on two streams, and emits with the first seen items when both+-- have emitted.  Once it emits, starts over.+--+-- >>> streamAuto' collectB [(Blip 1, NoBlip), (Blip 2, Blip 'a'),(Blip 3, Blip 'b')]+-- [NoBlip, Blip (1, 'a'), Blip (3, 'b')]+--+-- Can be used to implement a sort of "parallel wait".+--+collectB :: (Serialize a, Serialize b)+         => Auto m (Blip a, Blip b) (Blip (a, b))+collectB = mkState _collectBF (Nothing, Nothing)++-- | The non-serializing/non-resuming version of 'collectB'.+collectB_ :: Auto m (Blip a, Blip b) (Blip (a, b))+collectB_ = mkState_ _collectBF (Nothing, Nothing)++_collectBF :: (Blip a, Blip b)+           -> (Maybe a, Maybe b)+           -> (Blip (a, b), (Maybe a, Maybe b))+_collectBF (b1, b2) (st1, st2) =+    case liftA2 (,) st1' st2' of+      Just (x, y) -> (Blip (x, y), (Nothing, Nothing))+      Nothing     -> (NoBlip     , (st1'   , st2'   ))+  where+    st1' = st1 <|> blip Nothing Just b1+    st2' = st2 <|> blip Nothing Just b2++ -- | Applies the given function to every emitted value, and suppresses all -- those for which the result is 'Nothing'.  Otherwise, lets it pass -- through with the value in the 'Just'.@@ -756,16 +831,40 @@ -- semantics, we have "Control.Auto.Interval". -- -- See the examples of 'emitOn' for more concrete good/bad use cases.+--+-- prop> onJusts == emitJusts id onJusts :: Auto m (Maybe a) (Blip a) onJusts = mkFunc (maybe NoBlip Blip) +-- | Like 'onJusts', except forks into two streams depending on if the+-- input is 'Left' or 'Right'.+--+-- Is only meaningful if you expect every 'Left'/'Right' choice to be+-- independent of the last.+--+-- prop> onEithers == emitEithers id+onEithers :: Auto m (Either a b) (Blip a, Blip b)+onEithers = mkFunc $ \ex -> case ex of+                              Left x  -> (Blip x, NoBlip)+                              Right x -> (NoBlip, Blip x)++-- | Like 'emitJusts', except forks into two streams depending on the+-- function's result being 'Left' or 'Right'.+--+-- Is only meaningful if you expect every 'Left'/'Right' choice to be+-- independent of the last.+emitEithers :: (a -> Either b c) -> Auto m a (Blip b, Blip c)+emitEithers f = mkFunc $ \x -> case f x of+                                 Left y  -> (Blip y, NoBlip)+                                 Right y -> (NoBlip, Blip y)+ -- | @'fromBlips' d@ is an 'Auto' that decomposes the incoming blip -- stream by constantly outputting @d@ except when the stream emits, and -- outputs the emitted value when it does. fromBlips :: a  -- ^ the "default value" to output when the input is not                 --   emitting.           -> Auto m (Blip a) a-fromBlips d = mkFunc (blip d id)+fromBlips d = mkFunc $ blip d id  -- | @'fromBlipsWith' d f@ is an 'Auto' that decomposes the incoming blip -- stream by constantly outputting @d@ except when the stream emits, and@@ -775,8 +874,17 @@               -> (a -> b)   -- ^ the function to apply to the emitted value                             --   whenever input is emitting.               -> Auto m (Blip a) b-fromBlipsWith d f = mkFunc (blip d f)+fromBlipsWith d f = mkFunc $ blip d f +-- | Collapse a blip stream of `a`s into a stream of `Maybe a`'s+asMaybes :: Auto m (Blip a) (Maybe a)+asMaybes = mkFunc $ blip Nothing Just++-- | Take in a normal stream and a blip stream.  Behave like the normal+-- stream when the blip stream doesn't emit...but when it does, output the+-- emitted value instead.+substituteB :: Auto m (a, Blip a) a+substituteB = mkFunc $ \(x, b) -> blip x id b  -- | @'holdWith' y0@ is an 'Auto' whose output is always the /most recently -- emitted/ value from the input blip stream.  Before anything is emitted,
src/Control/Auto/Collection.hs view
@@ -61,9 +61,13 @@   -- ** Single input, single output   , mux   , mux_+  , muxI+  , muxI_   -- ** Multiple input, multiple output   , muxMany   , muxMany_+  , muxManyI+  , muxManyI_   -- * "Gathering"/accumulating collections   -- ** Single input, multiple output   , gather@@ -351,10 +355,6 @@ -- Whenever any of the internal 'Auto's return 'Nothing', they are removed -- from the collection. ----- Toy examples here are of limited use, but let's try it out.  Here we--- will have a 'dynMap_' that feeds each internal 'Auto' back to itself.--- The result of each is sent directly back to itself.--- -- >>> import qualified Data.IntMap as IM -- >>> let dm0 :: Auto' (IM.IntMap Int) (IM.IntMap Int) --         dm0 = proc x -> do@@ -530,8 +530,8 @@ -- -- See 'mux' for more notes. muxMany :: (Serialize k, Ord k, Monad m)-        => (k -> Auto m a b)    -- ^ function to create a new 'Auto' if-                                --   none at that key already exists+        => (k -> Auto m a b)  -- ^ function to create a new 'Auto' if+                              --   none at that key already exists         -> Auto m (Map k a) (Map k b) muxMany f = go mempty   where@@ -545,21 +545,21 @@     t     = _muxManyF f go  -- | The non-serializing/non-resuming version of 'muxMany'.-muxMany_ :: forall m a b k. (Ord k, Monad m)-         => (k -> Auto m a b)     -- ^ function to create a new 'Auto' if-                                  --   none at that key already exists+muxMany_ :: (Ord k, Monad m)+         => (k -> Auto m a b) -- ^ function to create a new 'Auto' if+                              --   none at that key already exists          -> Auto m (Map k a) (Map k b) muxMany_ f = go mempty   where-    go :: Map k (Auto m a b) -> Auto m (Map k a) (Map k b)+    -- go :: Map k (Auto m a b) -> Auto m (Map k a) (Map k b)     go = mkAutoM_ . _muxManyF f go  _muxManyF :: forall k m a b. (Ord k, Monad m)-          => (k -> Auto m a b)                           -- ^ f : make new Autos+          => (k -> Auto m a b)                          -- ^ f : make new Autos           -> (Map k (Auto m a b) -> Auto m (Map k a) (Map k b)) -- ^ go: make next step-          -> Map k (Auto m a b)                          -- ^ as: all current Autos-          -> Map k a                                     -- ^ xs: Inputs-          -> m (Map k b, Auto m (Map k a) (Map k b))     -- ^ Outputs, and next Auto.+          -> Map k (Auto m a b)                         -- ^ as: all current Autos+          -> Map k a                                    -- ^ xs: Inputs+          -> m (Map k b, Auto m (Map k a) (Map k b))    -- ^ Outputs, and next Auto. _muxManyF f go as xs = do     -- all the outputs of the autos with the present inputs; autos without     --   inputs are ignored.@@ -578,6 +578,86 @@     --   corresponding input.     steps :: Map k (m (b, Auto m a b))     steps = M.intersectionWith stepAuto allas xs+++-- | Like 'muxI', but holds 'Interval's instead.  When any given 'Interval'+-- turns "off", it's removed from the collection.  If its key is fed in+-- again, it'll be restarted with the initializing function.  On the actual+-- step when it turns "off", 'Nothing' will be returned.+muxI :: (Serialize k, Ord k, Monad m)+     => (k -> Interval m a b) -- ^ function to create a new 'Auto' if none at+                              --   that key already exists.+     -> Auto m (k, a) (Maybe b)+muxI f = dimap (uncurry M.singleton) (listToMaybe . M.elems) (muxManyI f)++-- | The non-serializing/non-resuming version of 'muxI'.+muxI_ :: (Ord k, Monad m)+      => (k -> Interval m a b)   -- ^ function to create a new 'Auto' if none at+                                 --   that key already exists+      -> Auto m (k, a) (Maybe b)+muxI_ f = dimap (uncurry M.singleton) (listToMaybe . M.elems) (muxManyI_ f)++-- | Like 'muxManyI', but holds 'Interval's instead.  When any given+-- 'Interval' turns "off", it's removed from the collection.  Only+-- 'Interval's that are "on" after the step will be present in the output+-- 'Map'.+muxManyI :: (Serialize k, Ord k, Monad m)+         => (k -> Interval m a b) -- ^ function to create a new 'Auto' if+                                  --   none at that key already exists+         -> Auto m (Map k a) (Map k b)+muxManyI f = go mempty+  where+    -- go :: Map k (Interval m a b) -> Auto m (Map k a) (Map k b)+    go as = mkAutoM l (s as) (t as)+    l     = do+      ks <- get+      let as = M.fromList (map (id &&& f) ks)+      go <$> mapM resumeAuto as+    s as  = put (M.keys as) *> mapM_ saveAuto as+    t     = _muxManyIF f go++-- | The non-serializing/non-resuming version of 'muxManyI'.+muxManyI_ :: (Ord k, Monad m)+          => (k -> Interval m a b) -- ^ function to create a new 'Auto' if+                                   --   none at that key already exists+          -> Auto m (Map k a) (Map k b)+muxManyI_ f = go mempty+  where+    -- go :: Map k (Interval m a b) -> Auto m (Map k a) (Map k b)+    go = mkAutoM_ . _muxManyIF f go++_muxManyIF :: forall k m a b. (Ord k, Monad m)+           => (k -> Interval m a b)                       -- ^ f : make new Autos+           -> (Map k (Interval m a b) -> Auto m (Map k a) (Map k b)) -- ^ go: make next step+           -> Map k (Interval m a b)                      -- ^ as: all current Autos+           -> Map k a                                     -- ^ xs: Inputs+           -> m (Map k b, Auto m (Map k a) (Map k b))     -- ^ Outputs, and next Auto.+_muxManyIF f go as xs = do+    -- all the outputs of the autos with the present inputs; autos without+    --   inputs are ignored.+    outs <- sequence steps+    let outs'  = M.mapMaybe filterDead outs   -- Nothings removed+        ys     = fmap fst outs'+        allas' = M.union (fmap snd outs') leftOuts+    return (ys, go allas')+  where+    -- new Autos, from the function.  Only on new ones not found in `as`.+    newas :: Map k (Interval m a b)+    newas = M.mapWithKey (\k _ -> f k) (M.difference xs as)+    -- all Autos, new and old.  Prefer the old ones.+    allas :: Map k (Interval m a b)+    allas = M.union as newas+    -- Step all the autos with all the inputs.  Lose the Autos that have no+    --   corresponding input.+    steps :: Map k (m (Maybe b, Interval m a b))+    steps = M.intersectionWith stepAuto allas xs+    -- Autos not being stepped+    leftOuts :: Map k (Interval m a b)+    leftOuts = M.difference allas steps+    -- Get out the result if Just, otherwise erase it all.+    filterDead :: (Maybe b, Interval m a b) -> Maybe (b, Interval m a b)+    filterDead (Just x, i) = Just (x, i)+    filterDead _           = Nothing  e2m :: Either (a, b) b -> (Maybe a, b) e2m (Left (x, y)) = (Just x , y)
src/Control/Auto/Core.hs view
@@ -827,7 +827,7 @@ --         Nothing -> do --           (y, a2') <- stepAuto a2 x --           return (y, switched a2')---     switched a = mkAutoM (switched <$> resumeAuto a)+--     switched a = mkAutoM l --                          (put True  *> saveAuto a) --                        $ \x -> do --                            (y, a') <- stepAuto a x@@ -1172,6 +1172,19 @@ -- -- (Compare with the example in 'accum') --+-- Note that this is more or less an encoding of 'scanl', that can be+-- "decoded" with 'streamAuto'':+--+-- >>> let myScanl f z = streamAuto' (accumD f z)+-- >>> scanl (+) 0 [1..10]+-- [0,3,6,10,15,21,28,36,45,55]+-- >>> myScanl (+) 0 [1..10]+-- [0,3,6,10,15,21,28,36,45]+--+-- The only difference is that you don't get the last element.  (You could+-- force it out, if you wanted, by feeding any nonsense value in --- even+-- 'undefined'! --- and getting the result)+-- accumD :: Serialize b          => (b -> a -> b)      -- ^ accumulating function          -> b                  -- ^ initial accumulator@@ -1308,8 +1321,8 @@  -- | When the underlying 'Monad'/'Applicative' @m@ is an 'Alternative', -- fork the input through each one and "squish" their results together--- inside the 'Alternative' context.  Somewhat rarely used, because who--- uses an 'Alternative' @m@?+-- inside the 'Alternative' context.  See 'runTraversableA' for similar use+-- cases. -- -- >>> streamAuto (arrM (mfilter even . Just)) [1..10] -- Nothing
src/Control/Auto/Effects.hs view
@@ -898,11 +898,15 @@ -- bar = arrM Just -- @ --+-- >>> streamAuto foo [2,4,6,7]+-- Nothing+-- >>> streamAuto' (runTraversableA foo) [2,4,6,7]+-- [Just 1, Just 2, Just 3, Nothing] -- >>> streamAuto (foo &&& bar) [2,4,6] -- Just [(1, 2),(2, 4),(3, 6)] -- >>> streamAuto (foo &&& bar) [2,4,6,7] -- Nothing--- >>> streamAuto' ('runTraversableA' foo '<|?>' 'runTraversableA' bar) [2,4,6,7]+-- >>> streamAuto' (runTraversableA foo <|?> runTraversableA bar) [2,4,6,7] -- [Just 1, Just 2, Just 3, Just 7] runTraversableA :: (Monad f, Traversable f)                 => Auto f a b           -- ^ 'Auto' run over traversable structure@@ -915,6 +919,7 @@                               y  = liftM fst o                               a' = liftM snd o                           in  (y, go a')+  -- | Wraps a "try" over an underlying 'IO' monad; if the Auto encounters a -- runtime exception while trying to "step" itself, it'll output a 'Left'
src/Control/Auto/Interval.hs view
@@ -243,7 +243,7 @@ --     'bindI' i2 . i1 :: 'Interval' m a b c -- @ ----- >>> let a1        = when (< 5) `compI` offFor 2+-- >>> let a1        = whenI (< 5) `compI` offFor 2 -- >>> streamAuto' a1 [1..6] -- [Nothing, Nothing, Just 3, Just 4, Nothing, Nothing] --@@ -743,3 +743,4 @@       -> Interval m a b   -- ^ ...to this one       -> Interval m a c compI f g = fmap join (during f) . g+
src/Control/Auto/Switch.hs view
@@ -33,6 +33,7 @@   -- * Sequential switching     (-->)   , (-?>)+  , switchIn   -- * Arbitrary switching   , switchFrom_   , switchOn_@@ -153,12 +154,46 @@         Nothing -> do           (y, a2') <- stepAuto a2 x           return (y, switched a2')-    switched a = mkAutoM (switched <$> resumeAuto a)+    switched a = mkAutoM l                          (put True  *> saveAuto a)                        $ \x -> do                            (y, a') <- stepAuto a x                            return (y, switched a') -- TODO: Add tests for the serialization here.++-- | @'switchIn' n a1 a2@ will behave like @a1@ for @n@ steps of output,+-- and then behave like @a2@ forever after.+--+-- More or less a more efficient/direct implementation of the common idiom:+--+-- @+-- onFor n a1 --> a2+-- @+--+--+switchIn :: Monad m+         => Int           -- ^ number of outputs before switching+         -> Auto m a b    -- ^ initial behavior+         -> Auto m a b    -- ^ switched behavior+         -> Auto m a b+switchIn n a1 a2 | n > 0     = mkAutoM l s t+                 | otherwise = switched a2+  where+    l = do+      flag <- get+      if flag+        then resumeAuto (switched a2)+        else switchIn <$> get <*> resumeAuto a1 <*> pure a2+    s = put False *> put n *> saveAuto a1+    t x = do+      (y, a1') <- stepAuto a1 x+      return (y, switchIn (n - 1) a1' a2)+    switched a = mkAutoM l+                         (put True *> saveAuto a)+                       $ \x -> do+                           (y, a') <- stepAuto a x+                           return (y, switched a')+  -- | Takes an 'Auto' who has both a normal output stream and a blip stream -- output stream, where the blip stream emits new 'Auto's.
src/Control/Auto/Time.hs view
@@ -36,6 +36,7 @@     count   , count_   -- * Manipulating time+  , priming   -- ** Delaying   , lastVal   , lastVal_@@ -47,8 +48,6 @@   , delayList_   , delayN   , delayN_-  -- ** "Priming"-  , priming   -- ** Stretching   , stretch   , stretch_