-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Denotative, locally stateful programming DSL & platform -- @package auto @version 0.4.3.0 -- | This module exposes an "unsafe" interface for working with the -- internal representation of "blip streams". If you are programming at -- the logic level or the application level, you should thoroughly be -- able to avoid importing this, and should be happy with importing the -- Blip type from Control.Auto and blip stream manipulators -- from Control.Auto.Blip. -- -- If, however, you are programming a framework, library, or backend, you -- might find it useful to manually create your own blip streams/sources. -- In this case, this module will be useful. -- -- It is important, as with most of this library in general, to always -- keep in mind when you are programming at the "logic" level, and when -- you are programming at the "backend" level. If you can justify that -- you are at the backend level and not at the logic level of whatever -- you are programming, then this is useful. -- -- Be sure, of course, that whatever blip streams you do manually -- construct and export preserve "Blip semantics", which is further -- defined in Control.Auto.Blip. -- -- You have been warned! module Control.Auto.Blip.Internal -- | When used in the context of an input or output of an Auto, a -- Blip a represents a stream that occasionally, at -- "independent" or "discrete" points, emits a value of type a. -- -- Contrast this to Interval, where things are meant to be "on" -- or "off" for contiguous chunks at a time; blip streams are "blippy", -- and Intervals are "chunky". -- -- It's here mainly because it's a pretty useful abstraction in the -- context of the many combinators found in various modules of this -- library. If you think of an Auto m a (Blip b) -- as producing a "blip stream", then there are various combinators and -- functions that are specifically designed to manipulate blip streams. -- -- For the purposes of the semantics of what Blip is supposed to -- represent, its constructors are hidden. (Almost) all of the various -- Blip combinators (and its very useful Functor instance) -- "preserve Blipness" --- one-at-a-time occurrences remain -- one-at-a-time under all of these combinators, and you should have -- enough so that direct access to the constructor is not needed. -- -- If you are creating a framework, library, or backend, you might want -- to manually create blip stream-producing Autos for your users -- to access. In this case, you can import the constructors and useful -- internal (and, of course, semantically unsafe) functions from -- Control.Auto.Blip.Internal. data Blip a NoBlip :: Blip a Blip :: !a -> Blip a -- | Merge two blip streams together; the result emits with either -- of the two merged streams emit. When both emit at the same time, emit -- the result of applying the given function on the two emitted values. -- -- Note that this might be too strict for some purposes; see -- mergeL and mergeR for lazier alternatives. merge :: (a -> a -> a) -> Blip a -> Blip a -> Blip a -- | Slightly more powerful merge, but I can't imagine a situation -- where this power is necessary. -- -- If only the first stream emits, emit with the first function applied -- to the value. If only the second stream emits, emit with the second -- function applied to the value. If both emit, then emit with the third -- function applied to both emitted values. merge' :: (a -> c) -> (b -> c) -> (a -> b -> c) -> Blip a -> Blip b -> Blip c -- | Merges two blip streams together into one, which emits either -- of the original blip streams emit. If both emit at the same time, the -- left (first) one is favored. -- -- Lazy on the second stream if the first stream is emitting. -- -- If we discount laziness, this is merge const. mergeL :: Blip a -> Blip a -> Blip a -- | Merges two blip streams together into one, which emits either -- of the original blip streams emit. If both emit at the same time, the -- right (second) one is favored. -- -- Lazy on the first stream if the second stream is emitting. -- -- If we discount laziness, this is merge (flip -- const). mergeR :: Blip a -> Blip a -> Blip a -- | Deconstruct a Blip by giving a default result if the -- Blip is non-occuring and a function to apply on the contents, -- if the Blip is occuring. -- -- Try not to use if possible, unless you are a framework developer. If -- you're just making an application, try to use the other various -- combinators in this library. It'll help you preserve the semantics of -- what it means to be Blippy. -- -- Analogous to maybe from Prelude. blip :: b -> (a -> b) -> Blip a -> b instance Typeable Blip instance Functor Blip instance Show a => Show (Blip a) instance Generic (Blip a) instance Datatype D1Blip instance Constructor C1_0Blip instance Constructor C1_1Blip instance NFData a => NFData (Blip a) instance Serialize a => Serialize (Blip a) instance Semigroup a => Monoid (Blip a) instance Semigroup a => Semigroup (Blip a) -- | This module defines and provides the core types, (smart) constructors, -- and general high and low-level utilities used by the auto -- library. -- -- Note that importing and using functions from this module in part voids -- some of the "semantic contracts" of the Auto types you get, so -- use with caution! -- -- A lot of low-level functionality is provided here which is most likely -- unnecessary for most applications; many are mostly for internal usage -- or advanced/fine-grained usage. It also isn't really enough to do too -- many useful things, either. It's recommended that you import -- Control.Auto instead, which re-organizes the more useful parts -- of this module in addition with useful parts of others to provide a -- nice packaged entry point. If something in here becomes useful for -- more than just fine-tuning or low-level tweaking, it is probably -- supposed to be in Control.Auto anyway. -- -- Information on how to use these types is available in the -- tutorial! module Control.Auto.Core -- | The Auto type. For this library, an Auto semantically -- representsdenotes a a relationship/ between an input and an -- output that is preserved over multiple steps, where that relationship -- is (optionally) maintained within the context of a monad. -- -- A lot of fancy words, I know...but you can think of an Auto as -- nothing more than a "stream transformer" of value streams. A stream of -- sequential input values come in one at a time, and a stream of outputs -- pop out one at a time, as well. -- -- Using the streamAuto function, you can "unwrap" the inner -- value stream transformer from any Auto: if a :: Auto -- m a b, streamAuto lets you turn it into an [a] -> -- m [b]. "Give me a stream of as, one at a time, and I'll -- give you a list of bs, matching a relationship to your stream -- of as." -- --
--   -- unwrap your inner [a] -> m [b]!
--   streamAuto :: Monad m => Auto m a b -> ([a] -> m [b])
--   
-- -- You can also turn an Auto m a b into an effects -- stream that executes effects sequentially with -- toEffectStream and streamAutoEffects, so you can run -- it with a ListT-compatible library like pipes. -- -- There's a handy type synonym Auto' for relationships that don't -- really need a monadic context; the m is just Identity: -- --
--   type Auto' = Auto Identity
--   
-- -- So if you had an a :: Auto' a b, you can use -- streamAuto' to "unwrap" the inner stream transformer, [a] -- -> [b]. -- --
--   -- unwrap your inner [a] -> [b]!
--   streamAuto' :: Auto' a b -> ([a] -> [b])
--   
-- -- All of the Autos given in this library maintain some sort of -- semantic relationship between streams --- for some, the outputs might -- be the inputs with a function applied; for others, the outputs might -- be the cumulative sum of the inputs. -- -- See the tutorial for more information! -- -- Operationally, an Auto m a b is implemented as a -- "stateful function". A function from an a where, every time -- you "apply" it, you get a b and an "updated -- Auto"/function with updated state. -- -- You can get this function using stepAuto: -- --
--   stepAuto :: Auto m a b -> (a -> m (b, Auto m a b))
--   
-- -- Or, for Auto', stepAuto': -- --
--   stepAuto' :: Auto' a b -> (a -> (b, Auto' a b))
--   
-- -- "Give me an a and I'll give you a b and your -- "updated" Auto". -- -- Autos really are mostly useful because they can be composed, -- chained, and modified using their various typeclass instances, like -- Category, Applicative, Functor, Arrow, -- etc., and also with the combinators in this library. You can build -- complex programs as a complex Auto by building up smaller and -- smaller components. See the tutorial for more information on this. -- -- This type also contains information on its own serialization, so you -- can serialize and re-load the internal state to binary or disk. See -- the "serialization" section in the documentation for -- Control.Auto.Core, or the documentation for mkAutoM for -- more details. data Auto m a b -- | Special case of Auto where the underlying Monad is -- Identity. -- -- Instead of "wrapping" an [a] -> m [b], it "wraps" an -- [a] -> [b]. type Auto' = Auto Identity -- | Returns a string representation of the internal constructor of the -- Auto. Useful for debugging the result of compositions and -- functions and seeing how they affect the internal structure of the -- Auto. -- -- In the order of efficiency, AutoFuncs tend to be faster than -- AutoStates tend to be faster than AutoArbs. However, -- when composing one with the other (using Category or -- Applicative), the two have to be "reduced" to the greatest -- common denominator; composing an AutoFunc with an -- AutoArb produces an AutoArb. -- -- More benchmarking is to be done to be able to rigorously say what -- these really mean, performance wise. autoConstr :: Auto m a b -> String -- | Re-structure Auto internals to use the Arb -- ("arbitrary") constructors, as recursion-based mealy machines. -- -- Mostly here for performance comparisons and benchmarking purposes. toArb :: Monad m => Auto m a b -> Auto m a b -- | In theory, "purifying" an Auto'" should prep it for faster -- evaluation when used with stepAuto' or streamAuto'. -- But the benchmarks have not been run yet, so stay tuned! -- -- TODO: Benchmark purifyAuto :: Auto' a b -> Auto' a b -- | Runs the Auto through one step. -- -- That is, given an Auto m a b, returns a function that -- takes an a and returns a b and an "updated"/"next" -- Auto; an a -> m (b, Auto m a b). -- -- This is the main way of running an Auto "step by step", so if -- you have some sort of game loop that updates everything every "tick", -- this is what you're looking for. At every loop, gather input -- a, feed it into the Auto, "render" the result -- b, and get your new Auto to run the next time. -- -- Here is an example with sumFrom 0, the Auto -- whose output is the cumulative sum of the inputs, and an underying -- monad of Identity. Here, -- --
--   stepAuto :: Auto Identity Int Int
--            -> (Int -> Identity (Int, Auto Identity Int Int))
--   
-- -- Every time you "step", you give it an Int and get a resulting -- Int (the cumulative sum) and the "updated Auto", with -- the updated accumulator. -- --
--   >>> let a0 :: Auto Identity Int Int
--           a0 = sumFrom 0
--   
--   >>> let Identity (res1, a1) = stepAuto a0 4      -- run with 4
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> let Identity (res2, a2) = stepAuto a1 5      -- run with 5
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> let Identity (res3, _ ) = stepAuto a2 3      -- run with 3
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- By the way, for the case where your Auto is under -- Identity, we have a type synomym Auto'...and a -- convenience function to make "running" it more streamlined: -- --
--   >>> let a0 :: Auto' Int Int
--           a0 = sumFrom 0
--   
--   >>> let (res1, a1) = stepAuto' a0 4          -- run with 4
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> let (res2, a2) = stepAuto' a1 5          -- run with 5
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> let (res3, _ ) = stepAuto' a2 3          -- run with 3
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- But, if your Auto actaully has effects when being stepped, -- stepAuto will execute them: -- --
--   >>> let a0 :: Auto IO Int Int
--           a0 = effect (putStrLn "hey!") *> sumFrom 0
--   
--   >>> (res1, a1) <- stepAuto a0 4              -- run with 4
--   hey!         -- IO effect
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> (res2, a2) <- stepAuto a1 5              -- run with 5
--   hey!         -- IO effect
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> (res3, _ ) <- stepAuto a2 3              -- run with 3
--   hey!         -- IO effect
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- (Here, effect (putStrLn "hey") is an -- Auto IO Int (), which ignores its input and just -- executes putStrLn "hey" every time it is run. When we -- use *> from Control.Applicative, we "combine" the two -- Autos together and run them both on each input (4, 5, -- 3...)...but for the "final" output at the end, we only return the -- output of the second one, sumFrom 0 (5, 9, 12...)) -- -- If you think of an Auto m a b as a "stateful function" -- a -> m b, then stepAuto lets you "run" it. -- -- In order to directly run an Auto on a stream, an [a], -- use streamAuto. That gives you an [a] -> m [b]. stepAuto :: Monad m => Auto m a b -> a -> m (b, Auto m a b) -- | Runs an Auto' through one step. -- -- That is, given an Auto' a b, returns a function that -- takes an a and returns a b and an "updated"/"next" -- Auto'; an a -> (b, Auto' a b). -- -- See stepAuto documentation for motivations, use cases, and more -- details. You can use this instead of stepAuto when your -- underyling monad is Identity, and your Auto doesn't -- produce any effects. -- -- Here is an example with sumFrom 0, the Auto' -- whose output is the cumulative sum of the inputs -- --
--   stepAuto' :: Auto' Int Int
--             -> (Int -> (Int, Auto' Int Int))
--   
-- -- Every time you "step", you give it an Int and get a resulting -- Int (the cumulative sum) and the "updated Auto'", with -- the updated accumulator. -- --
--   >>> let a0 :: Auto' Int Int
--           a0 = sumFrom 0
--   
--   >>> let (res1, a1) = stepAuto' a0 4          -- run with 4
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> let (res2, a2) = stepAuto' a1 5          -- run with 5
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> let (res3, _ ) = stepAuto' a2 3          -- run with 3
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- If you think of an Auto' a b as a "stateful function" -- a -> b, then stepAuto' lets you "run" it. -- -- In order to directly run an Auto' on a stream, an [a], -- use streamAuto'. That gives you an [a] -> [b]. stepAuto' :: Auto' a b -> a -> (b, Auto' a b) -- | Like stepAuto, but drops the "next Auto" and just gives -- the result. evalAuto :: Monad m => Auto m a b -> a -> m b -- | Like stepAuto', but drops the "next Auto'" and just -- gives the result. evalAuto for Auto'. evalAuto' :: Auto' a b -> a -> b -- | Like stepAuto, but drops the result and just gives the "updated -- Auto". execAuto :: Monad m => Auto m a b -> a -> m (Auto m a b) -- | Like stepAuto', but drops the result and just gives the -- "updated Auto'". execAuto for Auto'. execAuto' :: Auto' a b -> a -> Auto' a b -- | Encode an Auto and its internal state into a ByteString. encodeAuto :: Auto m a b -> ByteString -- | Resume an Auto from its ByteString serialization, -- giving a Left if the deserialization is not possible. decodeAuto :: Auto m a b -> ByteString -> Either String (Auto m a b) -- | Returns a Put --- instructions (from Data.Serialize) on -- how to "freeze" the Auto, with its internal state, and save it -- to a binary encoding. It can later be reloaded and "resumed" by -- 'resumeAuto'/'decodeAuto'. saveAuto :: Auto m a b -> Put -- | Returns a Get from an Auto --- instructions (from -- Data.Serialize) on taking a ByteString and "restoring" the -- originally saved Auto, in the originally saved state. resumeAuto :: Auto m a b -> Get (Auto m a b) -- | Takes an Auto that is serializable/resumable and returns an -- Auto that is not. That is, when it is "saved", saves no data, -- and when it is "resumed", resets itself back to the initial -- configuration every time; in other words, decodeAuto -- (unserialize a) bs = Right (unserialize a). Trying to "resume" it -- will just always give itself, unchanged. unserialize :: Monad m => Auto m a b -> Auto m a b -- | Swaps out the underlying Monad of an Auto using the -- given monad morphism "transforming function", a natural -- transformation. -- -- Basically, given a function to "swap out" any m a with an -- m' a, it swaps out the underlying monad of the Auto. -- -- This forms a functor, so you rest assured in things like this: -- --
--   hoistA id == id
--   hoistA f a1 . hoistA f a2 == hoistA f (a1 . a2)
--   
hoistA :: (Monad m, Monad m') => (forall c. m c -> m' c) -> Auto m a b -> Auto m' a b -- | Generalizes an Auto' a b to an Auto m a -- b' for any Monad m, using hoist. -- -- You generally should be able to avoid using this if you never directly -- write any Auto's and always write 'Auto m' parameterized over -- all Monads, but...in case you import one from a library or -- something, you can use this. generalizeA :: Monad m => Auto' a b -> Auto m a b -- | Abstraction over lower-level funging with serialization; lets you -- modify the result of an Auto by being able to intercept the -- (b, Auto m a b) output and return a new output value -- m c. -- -- Note that this is a lot like fmap: -- --
--   fmap :: (b -> c) -> Auto m a b -> Auto m a c
--   
-- -- Except gives you access to both the b and the "updated -- Auto"; instead of an b -> c, you get to pass a -- (b, Auto m a b) -> m c. -- -- Basically experimenting with a bunch of abstractions over different -- lower-level modification of Autos, because making sure the -- serialization works as planned can be a bit difficult. interceptO :: Monad m => ((b, Auto m a b) -> m c) -> Auto m a b -> Auto m a c -- | Construct the Auto whose output is always the given value, -- ignoring its input. -- -- Provided for API constency, but you should really be using pure -- from the Applicative instance, from Control.Applicative, -- which does the same thing. mkConst :: b -> Auto m a b -- | Construct the Auto that always "executes" the given monadic -- value at every step, yielding the result as its output and ignoring -- its input. -- -- Provided for API consistency, but you shold really be using -- effect from Control.Auto.Effects, which does the same -- thing. mkConstM :: m b -> Auto m a b -- | Construct a stateless Auto that simply applies the given (pure) -- function to every input, yielding the output. The output stream is -- just the result of applying the function to every input. -- --
--   streamAuto' (mkFunc f) = map f
--   
-- -- This is rarely needed; you should be using arr from the -- Arrow instance, from Control.Arrow. mkFunc :: (a -> b) -> Auto m a b -- | Construct a stateless Auto that simply applies and executes the -- givne (monadic) function to every input, yielding the output. The -- output stream is the result of applying the function to every input, -- executing/sequencing the action, and returning the returned value. -- --
--   streamAuto (mkFuncM f) = mapM f
--   
-- -- It's recommended that you use arrM from -- Control.Auto.Effects. This is only really provided for -- consistency. mkFuncM :: (a -> m b) -> Auto m a b -- | Construct an Auto from a state transformer: an a -> s -- -> (b, s) gives you an Auto m a b, for any -- Monad m. At every step, it takes in the a -- input, runs the function with the stored internal state, returns the -- b result, and now contains the new resulting state. You have -- to intialize it with an initial state, of course. -- -- From the "stream transformer" point of view, this is rougly equivalent -- to mapAccumL from Data.List, with the function's -- arguments and results in the backwards order. -- --
--   streamAuto' (mkState f s0) = snd . mapAccumL (\s x -> swap (f x s))
--   
-- -- Try not to use this if it's ever avoidable, unless you're a framework -- developer or something. Try make something by combining/composing the -- various Auto combinators. -- -- If your state s does not have a Serialize instance, -- then you should either write a meaningful one, provide the -- serialization methods manually with mkState', or throw away -- serializability and use mkState_. mkState :: Serialize s => (a -> s -> (b, s)) -> s -> Auto m a b -- | A version of mkState, where the internal state isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See mkState for more details. -- -- Useful if your state s cannot have a meaningful -- Serialize instance. mkState_ :: (a -> s -> (b, s)) -> s -> Auto m a b -- | Construct an Auto from a "monadic" state transformer: a -- -> s -> m (b, s) gives you an Auto m a b. -- At every step, it takes in the a input, runs the function -- with the stored internal state and "executes" the m (b, s) to -- get the b output, and stores the s as the new, -- updated state. Must be initialized with an initial state. -- -- Try not to use this if it's ever avoidable, unless you're a framework -- developer or something. Try make something by combining/composing the -- various Auto combinators. -- -- This version is a wrapper around mkAuto, that keeps track of -- the serialization and re-loading of the internal state for you, so you -- don't have to deal with it explicitly. -- -- If your state s does not have a Serialize instance, -- then you should either write a meaningful one, provide the -- serialization methods manually with mkStateM', or throw away -- serializability and use mkStateM_. mkStateM :: Serialize s => (a -> s -> m (b, s)) -> s -> Auto m a b -- | A version of mkStateM, where the internal state isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See mkStateM for more details. -- -- Useful if your state s cannot have a meaningful -- Serialize instance. mkStateM_ :: (a -> s -> m (b, s)) -> s -> Auto m a b -- | A version of mkState, where the internal state doesn't have a -- Serialize instance, so you provide your own instructions for -- getting and putting the state. -- -- See mkState for more details. mkState' :: Get s -> (s -> Put) -> (a -> s -> (b, s)) -> s -> Auto m a b -- | A version of mkStateM, where the internal state doesn't have a -- Serialize instance, so you provide your own instructions for -- getting and putting the state. -- -- See mkStateM for more details. mkStateM' :: Get s -> (s -> Put) -> (a -> s -> m (b, s)) -> s -> Auto m a b -- | Construct an Auto from a "folding" function: b -> a -- -> b yields an Auto m a b. Basically acts like -- a foldl or a scanl. There is an internal accumulator -- that is "updated" with an a at every step. Must be given an -- initial accumulator. -- -- Example: an Auto that sums up all of its input. -- --
--   >>> let summer = accum (+) 0
--   
--   >>> let (sum1, summer')  = stepAuto' summer 3
--   
--   >>> sum1
--   3
--   
--   >>> let (sum2, summer'') = stepAuto' summer' 10
--   
--   >>> sum2
--   13
--   
--   >>> streamAuto'  summer'' [1..10]
--   [14,16,19,23,28,34,41,49,58,68]
--   
-- -- If your accumulator b does not have a Serialize -- instance, then you should either write a meaningful one, or throw away -- serializability and use accum_. accum :: Serialize b => (b -> a -> b) -> b -> Auto m a b -- | A version of accum, where the internal accumulator isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See accum for more details. -- -- Useful if your accumulator b cannot have a meaningful -- Serialize instance. accum_ :: (b -> a -> b) -> b -> Auto m a b -- | Construct an Auto from a "monadic" "folding" function: b -- -> a -> m b yields an Auto m a b. Basically -- acts like a foldM or scanM (if it existed). here is an -- internal accumulator that is "updated" with an input a with -- the result of the executed m b at every step. Must be given -- an initial accumulator. -- -- See accum for more details. -- -- If your accumulator b does not have a Serialize -- instance, then you should either write a meaningful one, or throw away -- serializability and use accumM_. accumM :: (Serialize b, Monad m) => (b -> a -> m b) -> b -> Auto m a b -- | A version of 'accumM_, where the internal accumulator isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See accumM for more details. -- -- Useful if your accumulator b cannot have a meaningful -- Serialize instance. accumM_ :: Monad m => (b -> a -> m b) -> b -> Auto m a b -- | A "delayed" version of accum, where the first output is the -- initial state of the accumulator, before applying the folding -- function. Useful in recursive bindings. -- --
--   >>> let summerD = accumD (+) 0
--   
--   >>> let (sum1, summerD')  = stepAuto' summerD 3
--   
--   >>> sum1
--   0
--   
--   >>> let (sum2, summerD'') = stepAuto' summerD' 10
--   
--   >>> sum2
--   3
--   
--   >>> streamAuto'  summerD'' [1..10]
--   [13,14,16,19,23,28,34,41,49,58]
--   
-- -- (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) -> b -> Auto m a b -- | The non-resuming/non-serializing version of accumD. accumD_ :: (b -> a -> b) -> b -> Auto m a b -- | A "delayed" version of accumM, where the first output is the -- initial state of the accumulator, before applying the folding -- function. Useful in recursive bindings. accumMD :: (Serialize b, Monad m) => (b -> a -> m b) -> b -> Auto m a b -- | The non-resuming/non-serializing version of accumMD. accumMD_ :: Monad m => (b -> a -> m b) -> b -> Auto m a b -- | Construct an Auto by explicity giving its serialization, -- deserialization, and the function from a to a b and -- "updated Auto". -- -- Ideally, you wouldn't have to use this unless you are making your own -- framework. Try your best to make what you want by assembling primtives -- together. Working with serilization directly is hard. -- -- See mkAutoM for more detailed instructions on doing this right. mkAuto :: Get (Auto m a b) -> Put -> (a -> (b, Auto m a b)) -> Auto m a b -- | Like mkAuto, but without any way of meaningful serializing or -- deserializing. -- -- Be careful! This Auto can still carry arbitrary internal state, -- but it cannot be meaningfully serialized or re-loaded/resumed. You can -- still pretend to do so using -- 'resumeAuto'/'saveAuto'/'encodeAuto'/'decodeAuto' (and the type system -- won't stop you), but when you try to "resume"/decode it, its state -- will be lost. mkAuto_ :: (a -> (b, Auto m a b)) -> Auto m a b -- | Construct an Auto by explicitly giving its serializiation, -- deserialization, and the (monadic) function from a to a -- b and the "updated Auto". -- -- See the "serialization" section in the Control.Auto.Core module -- for more information. -- -- Ideally, you wouldn't have to use this unless you are making your own -- framework. Try your best to make what you want by assembling primtives -- together. -- -- But sometimes you have to write your own combinators, and you're going -- to have to use mkAutoM to make it work. -- -- Sometimes, it's simple: -- --
--   fmap :: (a -> b) -> Auto r a -> Auto r b
--   fmap f a0 = mkAutoM (do aResumed <- resumeAuto a0
--                           return (fmap f aResumed)  )
--                       (saveAuto a0)
--                       $ x -> do
--                           (y, a1) <- stepAuto a0 x
--                           return (f y, fmap f a1)
--   
-- -- Serializing fmap f a0 is just the same as serializing -- a0. And to resume it, we resume a0 to get a resumed -- version of a0, and then we apply fmap f to -- the Auto that we resumed. -- -- Also another nice "simple" example is: -- --
--   catchA :: Exception e
--          => Auto IO a b
--          -> Auto IO a (Either e b)
--   catchA a = mkAutoM (do aResumed <- resumeAuto a
--                          return (catchA aResumed) )
--                      (saveAuto a)
--                    $ x -> do
--                        eya' <- try $ stepAuto a x
--                        case eya' of
--                          Right (y, a') -> return (Right y, catchA a')
--                          Left e        -> return (Left e , catchA a )
--   
-- -- Which is basically the same principle, in terms of serializing and -- resuming strategies. -- -- When you have "switching" --- things that behave like different -- Autos at different points in time --- then things get a little -- complicated, because you have to figure out which Auto to -- resume. -- -- For example, let's look at the source of -?>: -- --
--   (-?>) :: Monad m
--         => Interval m a b   -- ^ initial behavior
--         -> Interval m a b   -- ^ final behavior, when the initial
--                             --   behavior turns off.
--         -> Interval m a b
--   a1 -?> a2 = mkAutoM l s t
--     where
--       l = do
--         flag <- get
--         if flag
--           then resumeAuto (switched a2)
--           else (-?> a2) $ resumeAuto a1
--       s = put False *> saveAuto a1
--       t x = do
--         (y1, a1') <- stepAuto a1 x
--         case y1 of
--           Just _  ->
--             return (y1, a1' -?> a2)
--           Nothing -> do
--             (y, a2') <- stepAuto a2 x
--             return (y, switched a2')
--       switched a = mkAutoM l
--                            (put True  *> saveAuto a)
--                          $ x -> do
--                              (y, a') <- stepAuto a x
--                              return (y, switched a')
--   
-- -- We have to invent a serialization and reloading scheme, taking into -- account the two states that the resulting Auto can be in: -- --
    --
  1. Initially, it is behaving like a1. So, to save it, we put -- a flag saying that we are still in stage 1 (False), and then -- put a1's current serialization data.
  2. --
  3. After the switch, it is behaving like a2. So, to save it, -- we put a flag saying that we are now in stage 2 (True), and -- then put a2's current.
  4. --
-- -- Now, when we resume a1 -?> a2, -- resumeAuto on a1 -?> a2 will give us -- l. So the Get we use --- the process we use to resume -- the entire a1 -?> a2, will start at the -- initial Get/loading function, l here. We have to -- encode our branching and resuming/serialization scheme into the -- initial, front-facing l. So l has to check for the -- flag, and if the flag is true, load in the data for the switched -- state; otherwise, load in the data for the pre-switched state. -- -- Not all of them are this tricky. Mostly "switching" combinators will -- be tricky, because switching means changing what you are serializing. -- -- This one might be considerably easier, because of mapM: -- --
--   zipAuto :: Monad m
--           => a                -- ^ default input value
--           -> [Auto m a b]     -- ^ Autos to zip up
--           -> Auto m [a] [b]
--   zipAuto x0 as = mkAutoM (zipAuto x0 $ mapM resumeAuto as)
--                           (mapM_ saveAuto as)
--                           $ xs -> do
--                               res <- zipWithM stepAuto as (xs ++ repeat x0)
--                               let (ys, as') = unzip res
--                               return (ys, zipAuto x0 as')
--   
-- -- To serialize, we basically sequence saveAuto over all of the -- internal Autos --- serialize each of their serialization data -- one-by-one one after the other in our binary. -- -- To load, we do the same thing; we go over every Auto in -- as and resumeAuto it, and then collect the results in -- a list --- a list of resumed Autos. And then we apply -- zipAuto x0 to that list of Autos, to get our -- resumed zipAuto x0 as. -- -- So, it might be complicated. In the end, it might be all worth it, -- too, to have implicit serialization compose like this. Think about -- your serialization strategy first. Step back and think about what you -- need to serialize at every step, and remember that it's _the initial_ -- "resuming" function that has to "resume everything"...it's not the -- resuming function that exists when you finally save your Auto, -- it's the resuming Get that was there at the beginning. -- For -?>, the intial l had to know how to "skip -- ahead". -- -- And of course as always, test. -- -- If you need to make your own combinator or transformer but are having -- trouble with the serializtion, feel free to contact me at -- justin@jle.im, on freenode at #haskell or -- #haskell-auto, open a github issue, etc. Just contact me -- somehow, I'll be happy to help! mkAutoM :: Get (Auto m a b) -> Put -> (a -> m (b, Auto m a b)) -> Auto m a b -- | Like mkAutoM, but without any way of meaningful serializing or -- deserializing. -- -- Be careful! This Auto can still carry arbitrary internal state, -- but it cannot be meaningfully serialized or re-loaded/resumed. You can -- still pretend to do so using -- 'resumeAuto'/'saveAuto'/'encodeAuto'/'decodeAuto' (and the type system -- won't stop you), but when you try to "resume"/decode it, its state -- will be reset. mkAutoM_ :: (a -> m (b, Auto m a b)) -> Auto m a b -- | Force the serializing components of an Auto. -- -- TODO: Test if this really works forceSerial :: Auto m a b -> Auto m a b -- | A special Auto that acts like the id Auto, but -- forces results as they come through to be fully evaluated, when -- composed with other Autos. -- -- TODO: Test if this really works forcer :: NFData a => Auto m a a -- | A special Auto that acts like the id Auto, but -- forces results as they come through to be evaluated to Weak Head -- Normal Form, with seq, when composed with other Autos. -- -- TODO: Test if this really works seqer :: Auto m a a instance Typeable Auto instance (Monad m, Floating b) => Floating (Auto m a b) instance (Monad m, Fractional b) => Fractional (Auto m a b) instance (Monad m, Num b) => Num (Auto m a b) instance (Monad m, IsString b) => IsString (Auto m a b) instance (Monad m, Monoid b) => Monoid (Auto m a b) instance (Monad m, Semigroup b) => Semigroup (Auto m a b) instance MonadFix m => ArrowLoop (Auto m) instance Monad m => ArrowChoice (Auto m) instance Monad m => Arrow (Auto m) instance MonadFix m => Costrong (Auto m) instance Monad m => Choice (Auto m) instance Monad m => Strong (Auto m) instance Monad m => Profunctor (Auto m) instance Monad m => Category (Auto m) instance (Monad m, Alternative m) => Alternative (Auto m a) instance Monad m => Applicative (Auto m a) instance Monad m => Functor (Auto m a) -- | This module provides combinators and utilities for working with the -- semantic concept of "intervals": an Auto whose output stream is -- "on" or "off" for (conceputally) contiguous chunks of time. module Control.Auto.Interval -- | Represents a relationship between an input and an output, where the -- output can be "on" or "off" (using Just and Nothing) for -- contiguous chunks of time. -- -- "Just" a type alias for Auto m a (Maybe b). If -- you ended up here with a link...no worries! If you see -- Interval m a b, just think Auto m a -- (Maybe b) for type inference/type checking purposes. -- -- If you see something of type Interval, you can rest assured -- that it has "interval semantics" --- it is on and off for meaningfully -- contiguous chunks of time, instead of just on and off willy nilly. If -- you have a function that expects an Interval, then the function -- expects its argument to behave in this way. type Interval m a b = Auto m a (Maybe b) -- | Interval, specialized with Identity as its underlying -- Monad. Analogous to Auto' for Auto. type Interval' a b = Auto' a (Maybe b) -- | The output stream is alwayas off, regardless of the input. -- -- Note that any monadic effects of the input Auto when composed -- with off are still executed, even though their result value is -- suppressed. -- --
--   off == pure Nothing
--   
off :: Interval m a b -- | The output stream is always on, with exactly the value of the -- corresponding input. -- --
--   toOn == arr Just
--   
toOn :: Interval m a a -- | An "interval collapsing" Auto. A stream of on/off values comes -- in; the output is the value of the input when the input is on, and the -- "default value" when the input is off. -- -- Much like fromMaybe from Data.Maybe. -- --
--   fromInterval d = arr (fromMaybe d)
--   
fromInterval :: a -> Auto m (Maybe a) a -- | An "interval collapsing" Auto. A stream of on/off values comes -- in; when the input is off, the output is the "default value". When the -- input is off, the output is the given function applied to the "on" -- value. -- -- Much like maybe from Data.Maybe. -- --
--   fromIntervalWith d f = arr (maybe d f)
--   
fromIntervalWith :: b -> (a -> b) -> Auto m (Maybe a) b -- | For onFor n, the first n items in the output -- stream are always "on" (passing through with exactly the value of the -- corresponding input); for the rest, the output stream is always "off", -- suppressing all input values forevermore. -- -- If a number less than 0 is passed, 0 is used. onFor :: Int -> Interval m a a -- | For offFor n, the first n items in the output -- stream are always "off", suppressing all input; for the rest, the -- output stream is always "on", outputting exactly the value of the -- corresponding input. offFor :: Int -> Interval m a a -- | A combination of onFor and offFor; for window -- b e, the output stream will be "on" from item b to item -- e inclusive with the value of the corresponding input; for -- all other times, the output stream is always off, suppressing any -- input. window :: Int -> Int -> Interval m a a -- | The output is "on" with exactly the value of he corresponding input -- when the input passes the predicate, and is "off" otherwise. -- --
--   >>> let a = whenI (\x -> x >= 2 && x <= 4)
--   
--   >>> streamAuto' a [1..6]
--   [Nothing, Just 2, Just 3, Just 4, Nothing, Nothing]
--   
-- -- Careful when using this; you could exactly create an Interval -- that "breaks" "interval semantics"; for example, 'whenI even', when -- you know your input stream does not consist of chunks of even numbers -- and odd numbers at a time. whenI :: (a -> Bool) -> Interval m a a -- | Like whenI, but only allows values to pass whenever the input -- does not satisfy the predicate. Blocks whenever the predicate is true. -- --
--   >>> let a = unlessI (\x -> x < 2 || x > 4)
--   
--   >>> steamAuto' a [1..6]
--   [Nothing, Just 2, Just 3, Just 4, Nothing, Nothing]
--   
unlessI :: (a -> Bool) -> Interval m a a -- | Forks a common input stream between an Interval and an -- Auto, and returns, itself, a normal non-interval Auto.. -- If the output of the first one is "on", the output of the whole thing -- is that "on" value. Otherwise, the output is exactly that of the -- second one. -- --
--   >>> let a1 = (onFor 2 . pure "hello") <|!> pure "world"
--   
--   >>> take 5 . streamAuto' a1 $ repeat ()
--   ["hello", "hello", "world", "world", "world"]
--   
-- -- This one is neat because it associates from the right, so it can be -- "chained": -- --
--   >>> let a2 = onFor 2 . pure "hello"
--           <|!> onFor 4 . pure "world"
--           <|!> pure "goodbye!"
--   
--   >>> take 6 . streamAuto' a2 $ repeat ()
--   ["hello", "hello", "world", "world", "goodbye!", "goodbye!"]
--   
-- --
--   a <|!> b <|!> c
--   
-- -- associates as -- --
--   a <|!> (b <|!> c)
--   
-- -- So using this, you can "chain" a bunch of choices between intervals, -- and then at the right-most, "final" one, provide the default behavior. -- -- Warning: If your underlying monad produces effects, remember that -- both Autos are run at every step, along with any monadic -- effects, regardless of whether they are "on" or "off". (<|!>) :: Monad m => Interval m a b -> Auto m a b -> Auto m a b -- | Forks a common input stream between the two Intervals and -- returns, itself, an Interval. If the output of the first one is -- "on", the whole thing is on with that output. Otherwise, the output is -- exactly that of the second one. -- --
--   >>> let a = (onFor 2 . pure "hello") <|?> (onFor 4 . pure "world")
--   
--   >>> take 5 . streamAuto' a $ repeat ()
--   [Just "hello", Just "hello", Just "world", Just "world", Nothing]
--   
-- -- You can drop the parentheses, because of precedence; the above could -- have been written as: -- --
--   >>> let a' = onFor 2 . pure "hello" <|?> onFor 4 . pure "world"
--   
-- -- Warning: If your underlying monad produces effects, remember that -- both Autos are run at every step, along with any monadic -- effects, regardless of whether they are "on" or "off". -- -- Note that more often than not, <|!> is probably more -- useful. This is useful only in the case that you really, really want -- an interval at the end of it all. (<|?>) :: Monad m => Interval m a b -> Interval m a b -> Interval m a b -- | Forks an input stream between all Intervals in the list. The -- result is an Interval whose output is "on" when any of the -- original Intervals is on, with the value of the first -- "on" one. -- --
--   chooseInterval == foldr (<|?>) off
--   
chooseInterval :: Monad m => [Interval m a b] -> Interval m a b -- | Forks an input stream between all Intervals in the list, plus a -- "default Auto. The output is the value of the first "on" -- Interval; if there isn't any, the output from the "default -- Auto" is used. -- --
--   choose == foldr (<|!>)
--   
choose :: Monad m => Auto m a b -> [Interval m a b] -> Auto m a b -- | Takes two input streams --- a stream of normal values, and a blip -- stream. Before the first emitted value of the input blip stream, the -- output is always "off", suppressing all inputs. After the first -- emitted value of the input blip stream, the output is always "on" with -- the corresponding value of the first input stream. -- --
--   >>> let a = after . (count &&& inB 3)
--   
--   >>> take 6 . streamAuto' a $ repeat ()
--   [Nothing, Nothing, Just 2, Just 3, Just 4, Just 5]
--   
-- -- (count is the Auto that ignores its input and outputs -- the current step count at every step, and inB 3 is -- the Auto generating a blip stream that emits at the third -- step.) -- -- Be careful to remember that in the above example, count is -- still "run" at every step, and is progressed (and if it were an -- Auto with monadic effects, they would still be executed). It -- just isn't allowed to pass its output values through after -- until the blip stream emits. after :: Interval m (a, Blip b) a -- | Takes two input streams --- a stream of normal values, and a blip -- stream. Before the first emitted value of the input blip stream, the -- output is always "on" with the corresponding value of the first input -- stream. After the first emitted value of the input blip stream, -- the output will be "off" forever, suppressing all input. -- --
--   >>> let a = before . (count &&& inB 3)
--   
--   >>> take 5 . streamAuto' a $ repeat ()
--   [Just 0, Just 1, Nothing, Nothing, Nothing]
--   
-- -- (count is the Auto that ignores its input and outputs -- the current step count at every step, and inB 3 is -- the Auto generating a blip stream that emits at the third -- step.) -- -- Be careful to remember that in the above example, count is -- still "run" at every step, and is progressed (and if it were an -- Auto with monadic effects, they would still be executed). It -- just isn't allowed to pass its output values through before -- after the blip stream emits. before :: Interval m (a, Blip b) a -- | Takes three input streams: a stream of normal values, a blip stream of -- "turning-on" blips, and a blip stream of "turning-off" blips. After -- the first blip stream emits, the output will switch to "on" with the -- value of the first input stream. After the second blip stream emits, -- the output will switch to "off", supressing all inputs. An emission -- from the first stream toggles this "on"; an emission from the second -- stream toggles this "off". -- --
--   >>> let a = between . (count &&& (inB 3 &&& inB 5))
--   
--   >>> take 7 . streamAuto' a $ repeat ()
--   [Nothing, Nothing, Just 2, Just 3, Nothing, Nothing, Nothing]
--   
between :: Interval m (a, (Blip b, Blip c)) a -- | The output is constantly "on" with the last emitted value of the input -- blip stream. However, before the first emitted value, it is "off". -- value of the input blip stream. From then on, the output is always the -- last emitted value -- --
--   >>> let a = hold . inB 3
--   
--   >>> streamAuto' a [1..5]
--   [Nothing, Nothing, Just 3, Just 3, Just 3]
--   
-- -- If you want an Auto m (Blip a) a (no -- Nothing...just a "default value" before everything else), then -- you can use holdWith from Control.Auto.Blip...or also -- just hold with <|!> or fromInterval. hold :: Serialize a => Interval m (Blip a) a -- | The non-serializing/non-resuming version of hold. hold_ :: Interval m (Blip a) a -- | For holdFor n, The output is only "on" if there was an -- emitted value from the input blip stream in the last n steps. -- Otherwise, is off. -- -- Like hold, but it only "holds" the last emitted value for the -- given number of steps. -- --
--   >>> let a = holdFor 2 . inB 3
--   
--   >>> streamAuto' a [1..7]
--   [Nothing, Nothing, Just 3, Just 3, Nothing, Nothing, Nothing]
--   
holdFor :: Serialize a => Int -> Interval m (Blip a) a -- | The non-serializing/non-resuming version of holdFor. holdFor_ :: Int -> Interval m (Blip a) a -- | Stretches the last "on"/Just input over the entire range -- of following "off"/Nothing inputs. Holds on to the last -- Just until another one comes along. -- --
--   >>> streamAuto' holdJusts [Nothing, Just 1, Just 3, Nothing, Nothing, Just 5]
--   [Nothing, Just 1, Just 3, Just 3, Just 3, Just 5]
--   
holdJusts :: Serialize a => Interval m (Maybe a) a -- | The non-resuming/non-serializing version of holdJusts. holdJusts_ :: Interval m (Maybe a) a -- | Lifts an Auto m a b (transforming as -- into bs) into an Auto m (Maybe a) -- (Maybe b) (or, Interval m (Maybe a) -- b, transforming intervals of as into -- intervals of b. -- -- It does this by running the Auto as normal when the input is -- "on", and freezing itbeing "off" when the input is off/. -- --
--   >>> let a1 = during (sumFrom 0) . onFor 2 . pure 1
--   
--   >>> take 5 . streamAuto' a1 $ repeat ()
--   [Just 1, Just 2, Nothing, Nothing, Nothing]
--   
-- --
--   >>> let a2 = during (sumFrom 0) . offFor 2 . pure 1
--   
--   >>> take 5 . streamAuto' a2 $ repeat ()
--   [Nothing, Nothing, Just 1, Just 2, Just 3]
--   
-- -- (Remember that pure x is the Auto that ignores -- its input and constantly just pumps out x at every step) -- -- Note the difference between putting the sumFrom "after" the -- offFor in the chain with during (like the previous -- example) and putting the sumFrom "before": -- --
--   >>> let a3 = offFor 2 . sumFrom 0 . pure 1
--   
--   >>> take 5 . streamAuto' a3 $ repeat ()
--   [Nothing, Nothing, Just 3, Just 4, Just 5]
--   
-- -- In the first case (with a2), the output of pure -- 1 was suppressed by offFor, and during -- (sumFrom 0) was only summing on the times that the 1's -- were "allowed through"...so it only "starts counting" on the third -- step. -- -- In the second case (with a3), the output of the -- pure 1 is never suppressed, and went straight into the -- sumFrom 0. sumFrom is always summing, the -- entire time. The final output of that sumFrom 0 is -- suppressed at the end with offFor 2. during :: Monad m => Auto m a b -> Interval m (Maybe a) b -- | Composes two Intervals, the same way that . composes two -- Autos: -- --
--   (.)   :: Auto     m b c -> Auto     m a b -> Auto     m a c
--   compI :: Interval m b c -> Interval m a b -> Interval m a c
--   
-- -- Basically, if any Interval in the chain is "off", then the -- entire rest of the chain is "skipped", short-circuiting a la -- Maybe. -- -- (Users of libraries with built-in inhibition semantics like Yampa and -- netwire might recognize this as the "default" composition in those -- other libraries) -- -- As a contrived example, how about an Auto that only allows -- values through during a window...between, say, the second and fourth -- steps: -- --
--   >>> let window' start dur = onFor dur `compI` offFor (start - 1)
--   
--   >>> streamAuto' (window' 2 3)
--   [Nothing, Just 2, Just 3, Just 4, Nothing, Nothing]
--   
compI :: Monad m => Interval m b c -> Interval m a b -> Interval m a c -- | Lifts (more technically, "binds") an Interval m a -- b into an Interval m (Maybe a) b. -- -- Does this by running the Auto as normal when the input is "on", -- and freezing itbeing "off" when the input is off/. -- -- It's kind of like during, but the resulting Maybe -- (Maybe b)) is "joined" back into a Maybe -- b. -- --
--   bindI a == fmap join (during a)
--   
-- -- This is really an alternative formulation of compI; typically, -- you will be using compI more often, but this form can also be -- useful (and slightly more general). Note that: -- --
--   bindI f == compI f id
--   
-- -- This combinator allows you to properly "chain" ("bind") together -- series of inhibiting Autos. If you have an Interval -- m a b and an Interval m b c, you can chain them -- into an Interval m a c. -- --
--   f             :: Interval m a b
--   g             :: Interval m b c
--   bindI g . f :: Interval m a c
--   
-- -- (Users of libraries with built-in inhibition semantics like Yampa and -- netwire might recognize this as the "default" composition in those -- other libraries) -- -- See compI for examples of this use case. bindI :: Monad m => Interval m a b -> Interval m (Maybe a) b -- | This module contains various Autos that act as "producing" -- streams; they all ignore their input streams and produce output -- streams through a pure or monadic process. module Control.Auto.Generate -- | An Interval that ignores the input stream and just outputs -- items from the given list. Is "on" as long as there are still items in -- the list left, and "off" after there is nothing left in the list to -- output. -- -- Serializes itself by storing the entire rest of the list in binary, so -- if your list is long, it might take up a lot of space upon storage. If -- your list is infinite, it makes an infinite binary, so be careful! -- -- fromLongList can be used for longer lists or infinite lists; -- or, if your list can be boild down to an unfoldr, you can use -- unfold. -- -- fromList :: Serialize b => [b] -> Interval m a b -- | The non-resuming/non-serializing version of fromList. fromList_ :: [b] -> Interval m a b -- | A version of fromList that is safe for long or infinite lists, -- or lists with unserializable elements. -- -- There is a small cost in the time of loading/resuming, which is -- O(n) on the number of times the Auto had been stepped at the -- time of saving. This is because it has to drop the n first -- elements in the list, to "resume" to the proper position. -- -- fromLongList :: [b] -> Interval m a b -- | Lift a value. pure :: Applicative f => forall a. a -> f a -- | To get every output, executes the monadic action and returns the -- result as the output. Always ignores input. -- -- This is basically like an "effectful" pure: -- --
--   pure   :: b   -> Auto m a b
--   effect :: m b -> Auto m a b
--   
-- -- The output of pure is always the same, and the output of -- effect is always the result of the same monadic action. Both -- ignore their inputs. -- -- Fun times when the underling Monad is, for instance, -- Reader. -- --
--   >>> let a = effect ask    :: Auto (Reader b) a b
--   
--   >>> let r = evalAuto a () :: Reader b b
--   
--   >>> runReader r "hello"
--   "hello"
--   
--   >>> runReader r 100
--   100
--   
-- -- If your underling monad has effects (IO, State, -- Maybe, Writer, etc.), then it might be fun to take -- advantage of *> from Control.Applicative to "tack on" -- an effect to a normal Auto: -- --
--   >>> let a = effect (modify (+1)) *> sumFrom 0 :: Auto (State Int) Int Int
--   
--   >>> let st = streamAuto a [1..10]
--   
--   >>> let (ys, s') = runState st 0
--   
--   >>> ys
--   [1,3,6,10,15,21,28,36,45,55]
--   
--   >>> s'
--   10
--   
-- -- Our Auto a behaves exactly like sumFrom -- 0, except at each step, it also increments the underlying/global -- state by one. It is sumFrom 0 with an "attached -- effect". effect :: m b -> Auto m a b -- | Analogous to iterate from Prelude. Keeps accumulator -- value and continually applies the function to the accumulator at every -- step, outputting the result. -- -- The first result is the initial accumulator value. -- --
--   >>> take 10 . streamAuto' (iterator (*2) 1) $ repeat ()
--   [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
--   
iterator :: Serialize b => (b -> b) -> b -> Auto m a b -- | The non-resuming/non-serializing version of iterator. iterator_ :: (b -> b) -> b -> Auto m a b -- | Like iterator, but with a monadic function. iteratorM :: (Serialize b, Monad m) => (b -> m b) -> b -> Auto m a b -- | The non-resuming/non-serializing version of iteratorM. iteratorM_ :: Monad m => (b -> m b) -> b -> Auto m a b -- | Given a function from discrete enumerable inputs, iterates through all -- of the results of that function. -- --
--   >>> take 10 . streamAuto' (discreteF (^2) 0) $ repeat ()
--   [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
--   
discreteF :: (Enum c, Serialize c) => (c -> b) -> c -> Auto m a b -- | The non-resuming/non-serializing version of discreteF. discreteF_ :: Enum c => (c -> b) -> c -> Auto m a b -- | Analogous to unfoldr from Prelude. Creates an -- Interval (that ignores its input) by maintaining an internal -- accumulator of type c and, at every step, applying to the -- unfolding function to the accumulator. If the result is -- Nothing, then the Interval will turn "off" forever -- (output Nothing forever); if the result is Just (y, -- acc), then it will output y and store acc as -- the new accumulator. -- -- Given an initial accumulator. -- --
--   >>> let countFromTil n m = flip unfold n $ \i -> if i <= m
--                                                      then Just (i, i+1)
--                                                      else Nothing
--   
--   >>> take 8 . streamAuto' (countFromTil 5 10) $ repeat ()
--   [Just 5, Just 6, Just 7, Just 8, Just 9, Just 10, Nothing, Nothing]
--   
-- -- unfold f c0 behaves like overList -- (unfoldr f c0). unfold :: Serialize c => (c -> Maybe (b, c)) -> c -> Interval m a b -- | The non-resuming & non-serializing version of unfold. unfold_ :: (c -> Maybe (b, c)) -> c -> Interval m a b -- | Like unfold, but the unfolding function is monadic. unfoldM :: (Serialize c, Monad m) => (c -> m (Maybe (b, c))) -> c -> Interval m a b -- | The non-resuming & non-serializing version of unfoldM. unfoldM_ :: Monad m => (c -> m (Maybe (b, c))) -> c -> Interval m a b -- | Continually enumerate from the starting value, using succ. enumFromA :: (Serialize b, Enum b) => b -> Auto m a b -- | The non-serializing/non-resuming version of enumFromA. enumFromA_ :: Enum b => b -> Auto m a b -- | Various Autos describing relationships following common -- processes, like sumFrom, whose output is the cumulative sum of -- the input. -- -- Also has some Auto constructors inspired from digital signal -- processing signal transformation systems and statistical models. -- -- Note that all of these can be turned into an equivalent version acting -- on blip streams, with perBlip: -- --
--   sumFrom n           :: Num a => Auto m a a
--   perBlip (sumFrom n) :: Num a => Auto m (Blip a) (Blip a)
--   
module Control.Auto.Process -- | The stream of outputs is the cumulative/running sum of the inputs so -- far, starting with an initial count. -- -- The first output takes into account the first input. See -- sumFromD for a version where the first output is the initial -- count itself. -- --
--   sumFrom x0 = accum (+) x0
--   
sumFrom :: (Serialize a, Num a) => a -> Auto m a a -- | The non-resuming/non-serializing version of sumFrom. sumFrom_ :: Num a => a -> Auto m a a -- | Like sumFrom, except the first output is the starting count. -- --
--   >>> let a = sumFromD 5
--   
--   >>> let (y1, a') = stepAuto' a 10
--   
--   >>> y1
--   5
--   
--   >>> let (y2, _ ) = stepAuto' a' 3
--   
--   >>> y2
--   10
--   
-- --
--   >>> streamAuto' (sumFrom 0) [1..10]
--   [1,3,6,10,15,21,28,36,45,55]
--   
--   >>> streamAuto' (sumFromD 0) [1..10]
--   [0,1,3,6,10,15,21,28,36,45]
--   
-- -- It's sumFrom, but "delayed". -- -- Useful for recursive bindings, where you need at least one value to be -- able to produce its "first output" without depending on anything else. -- --
--   sumFromD x0 = sumFrom x0 . delay 0
--   
-- --
--   sumFromD x0 = delay x0 . sumFrom x0
--   
sumFromD :: (Serialize a, Num a) => a -> Auto m a a -- | The non-resuming/non-serializing version of sumFromD. sumFromD_ :: Num a => a -> Auto m a a -- | The output is the running/cumulative product of all of the inputs so -- far, starting from an initial product. -- --
--   productFrom x0 = accum (*) x0
--   
productFrom :: (Serialize a, Num a) => a -> Auto m a a -- | The non-resuming/non-serializing version of productFrom. productFrom_ :: Num a => a -> Auto m a a -- | The output is the the difference between the input and the previously -- received input. -- -- First result is a Nothing, so you can use <|!> or -- fromInterval or fromMaybe to get a "default first -- value". -- --
--   >>> streamAuto' deltas [1,6,3,5,8]
--   
--   >>> [Nothing, Just 5, Just (-3), Just 2, Just 3]
--   
-- -- Usage with <|!>: -- --
--   >>> let a = deltas <|!> pure 100
--   
--   >>> streamAuto' (deltas <|!> pure 100) [1,6,3,5,8]
--   [100, 5, -3, 2, 3]
--   
-- -- Usage with fromMaybe: -- --
--   >>> streamAuto' (fromMaybe 100 <$> deltas) [1,6,3,5,8]
--   [100, 5, -3, 2, 3]
--   
deltas :: (Serialize a, Num a) => Interval m a a -- | The non-resuming/non-serializing version of deltas. deltas_ :: Num a => Interval m a a -- | The output is the sum of the past inputs, multiplied by a moving -- window of weights. -- -- For example, if the last received inputs are [1,2,3,4] (from -- most recent to oldest), and the window of weights is -- [2,0.5,4], then the output will be 1*2 + 0.5*2 + -- 4*3, or 15. (The weights are assumed to be zero past the -- end of the weight window) -- -- The immediately received input is counted as a part of the history. -- -- Mathematically, y_n = w_0 * x_(n-0) + w_1 + x_(n-1) + w_2 * -- x_(n-1) + ..., for all ws in the weight window, where -- the first item is w_0. y_n is the nth -- output, and x_n is the nth input. -- -- Note that this serializes the history of the input...or at least the -- history as far back as the entire window of weights. (A weight list of -- five items will serialize the past five received items) If your weight -- window is very long (or infinite), then serializing is a bad idea! -- -- The second parameter is a list of a "starting history", or initial -- conditions, to be used when the actual input history isn't long -- enough. If you want all your initial conditions/starting history to be -- 0, just pass in []. -- -- Minus serialization, you can implement sumFrom as: -- --
--   sumFrom n = movingAverage (repeat 1) [n]
--   
-- -- And you can implement a version of deltas as: -- --
--   deltas = movingAverage [1,-1] []
--   
-- -- It behaves the same, except the first step outputs the initially -- received value. So it's realy a bit like -- --
--   (movingAverage [1,-1] []) == (deltas |! id)
--   
-- -- Where for the first step, the actual input is used instead of the -- delta. -- -- Name comes from the statistical model. movingAverage :: (Num a, Serialize a) => [a] -> [a] -> Auto m a a -- | The non-serializing/non-resuming version of movingAverage. movingAverage_ :: Num a => [a] -> [a] -> Auto m a a -- | Any linear time independent stream transformation can be encoded by -- the response of the transformation when given [1,0,0,0...], -- or 1 : repeat 0. So, given an LTI Auto, -- if you feed it 1 : repeat 0, the output is what is -- called an "impulse response function". -- -- For any LTI Auto, we can reconstruct the behavior of the -- original Auto given its impulse response. Give -- impulseResponse an impulse response, and it will -- recreate/reconstruct the original Auto. -- --
--   >>> let getImpulseResponse a = streamAuto' a (1 : repeat 0)
--   
--   >>> let sumFromImpulseResponse = getImpulseResponse (sumFrom 0)
--   
--   >>> streamAuto' (sumFrom 0) [1..10]
--   [1,3,6,10,15,21,28,36,45,55]
--   
--   >>> streamAuto' (impulseResponse sumFromImpulseResponse) [1..10]
--   [1,3,6,10,15,21,28,36,45,55]
--   
-- -- Use this function to create an LTI system when you know its impulse -- response. -- --
--   >>> take 10 . streamAuto' (impulseResponse (map (2**) [0,-1..])) $ repeat 1
--   [1.0,1.5,1.75,1.875,1.9375,1.96875,1.984375,1.9921875,1.99609375,1.998046875]
--   
-- -- All impulse response after the end of the given list is assumed to be -- zero. -- -- Mathematically, y_n = h_0 * x_(n-0) + h_1 + x_(n-1) + h_2 * -- x_(n-1) + ..., for all h_n in the input response, where -- the first item is h_0. -- -- Note that when this is serialized, it must serialize a number of input -- elements equal to the length of the impulse response list...so if you -- give an infinite impulse response, you might want to use -- impulseResponse_, or not serialize. -- -- By the way, impulseResponse ir == movingAverage ir -- []. impulseResponse :: (Num a, Serialize a) => [a] -> Auto m a a -- | The non-serializing/non-resuming version of impulseResponse. impulseResponse_ :: Num a => [a] -> Auto m a a -- | The output is the sum of the past outputs, multiplied by a moving -- window of weights. Ignores all input. -- -- For example, if the last outputs are [1,2,3,4] (from most -- recent to oldest), and the window of weights is [2,0.5,4], -- then the output will be 1*2 + 0.5*2 + 4*3, or 15. -- (The weights are assumed to be zero past the end of the weight window) -- -- Mathematically, y_n = w_1 * y_(n-1) + w_2 * y_(n-2) + ..., -- for all w in the weight window, where the first item is -- w_1. -- -- Note that this serializes the history of the outputs...or at least the -- history as far back as the entire window of weights. (A weight list of -- five items will serialize the past five outputted items) If your -- weight window is very long (or infinite), then serializing is a bad -- idea! -- -- The second parameter is a list of a "starting history", or initial -- conditions, to be used when the actual output history isn't long -- enough. If you want all your initial conditions/starting history to be -- 0, just pass in []. -- -- You can use this to implement any linear recurrence relationship, like -- he fibonacci sequence: -- --
--   >>> evalAutoN' 10 (autoRegression [1,1] [1,1]) ()
--   [2,3,5,8,13,21,34,55,89,144]
--   
--   >>> evalAutoN' 10 (fromList [1,1] --> autoRegression [1,1] [1,1]) ()
--   [1,1,2,3,5,8,13,21,34,55]
--   
-- -- Which is 1 times the previous value, plus one times the value before -- that. -- -- You can create a series that doubles by having it be just twice the -- previous value: -- --
--   >>> evalAutoN' 10 (autoRegression [2] [1]) ()
--   [2,,4,8,16,32,64,128,256,512,1024]
--   
-- -- Name comes from the statistical model. autoRegression :: (Num b, Serialize b) => [b] -> [b] -> Auto m a b -- | The non-serializing/non-resuming version of autoRegression. autoRegression_ :: Num b => [b] -> [b] -> Auto m a b -- | A combination of autoRegression and movingAverage. -- Inspired by the statistical model. -- -- Mathematically: -- --
--   y_n = wm_0 * x_(n-0) + wm_1 * x_(n-1) + wm_2 * x_(n-2) + ...
--                        + wa_1 * y_(n-1) + wa_2 * y_(n-1) + ...
--   
-- -- Where wm_ns are all of the "moving average" weights, where -- the first weight is wm_0, and wa_ns are all of the -- "autoregression" weights, where the first weight is wa_1. arma :: (Num a, Serialize a) => [a] -> [a] -> [a] -> [a] -> Auto m a a -- | The non-serializing/non-resuming version of arma. arma_ :: Num a => [a] -> [a] -> [a] -> [a] -> Auto m a a -- | The output is the running/cumulative mconcat of all of the -- input seen so far, starting with mempty. -- --
--   >>> streamauto' mappender . map Last $ [Just 4, Nothing, Just 2, Just 3]
--   [Last (Just 4), Last (Just 4), Last (Just 2), Last (Just 3)]
--   
--   >>> streamAuto' mappender ["hello","world","good","bye"]
--   ["hello","helloworld","helloworldgood","helloworldgoodbye"]
--   
-- --
--   mappender = accum mappend mempty
--   
mappender :: (Serialize a, Monoid a) => Auto m a a -- | The non-resuming/non-serializing version of mappender. mappender_ :: Monoid a => Auto m a a -- | The output is the running <>-sum (mappend for -- Semigroup) of all of the input values so far, starting with a -- given starting value. Basically like mappender, but with a -- starting value. -- --
--   >>> streamAuto' (mappendFrom (Max 0)) [Max 4, Max (-2), Max 3, Max 10]
--   [Max 4, Max 4, Max 4, Max 10]
--   
-- --
--   mappendFrom m0 = accum (<>) m0
--   
mappendFrom :: (Serialize a, Semigroup a) => a -> Auto m a a -- | The non-resuming/non-serializing version of mappender. mappendFrom_ :: Semigroup a => a -> Auto m a a -- | This module provides utilities for "running" and "unrolling" -- Autos. You'll find "enhanced" versions of stepAuto, -- mechanisms for running Autos "interactively" inside IO, -- monadic and non-monadic "self-runners" (provide the handlers, and the -- Auto just recursively runs intself), and finally, ways of -- "unrolling" the underlying Monad of Autos into more -- manageable and composable and easy to work with forms. module Control.Auto.Run -- | Lifts an Auto m a b to one that runs "through" a -- Traversable, Auto m (t a) (t b). It does this -- by running itself sequentially over every element "in" the -- Traversable at every input. -- -- This can be thought of as a polymorphic version of many other -- combinators in this library: -- --
--   during        = throughT :: Auto m a b -> Interval m (Maybe a) b
--   perBlip       = throughT :: Auto m a b -> Auto m (Blip a) (Blip b)
--   accelOverList = throughT :: Auto m a b -> Auto m [a] [b]
--   
-- -- The specialized versions will still be more performant, but this will -- be more general...you can run the Auto through an input -- IntMap, for example. -- -- Note that this is actually an endofunctor on the Auto -- Category. That is, for all Autos lifted and all lawful -- Traversables, usage should obey the laws: -- --
--   throughT id = id
--   throughT g . throughT f = throughT (g . f)
--   
throughT :: (Monad m, Traversable t) => Auto m a b -> Auto m (t a) (t b) -- | Stream an Auto over a list, returning the list of results. Does -- this "lazily" (over the Monad), so with most Monads, this should work -- fine with infinite lists. (That is, streamAuto -- (arrM f) behaves exactly like mapM f, -- and you can reason with Autos as if you'd reason with -- mapM on an infinite list) -- -- Note that, conceptually, this turns an Auto m a b into -- an [a] -> m [b]. -- -- See streamAuto' for a simpler example; here is one taking -- advantage of monadic effects: -- --
--   >>> let a = arrM print *> sumFrom 0 :: Auto IO Int Int
--   
--   >>> ys <- streamAuto a [1..5]
--   1                -- IO effects
--   2
--   3
--   4
--   5
--   
--   >>> ys
--   [1,3,6,10,15]    -- the result
--   
-- -- a here is like sumFrom 0, except at every -- step, prints the input item to stdout as a side-effect. -- -- Note that we use "stream" here slightly differently than in libraries -- like pipes or conduit. We don't stream over the -- m Monad (like IO)...we stream over the input -- elements. Using streamAuto on an infinite list allows you -- to "stop", for example, to find the result...but it will still -- sequence all the *effects*. -- -- For example: -- --
--   >>> take 10 <$> streamAuto (arrM print *> id) [1..]
--   
-- -- Will execute print on every element before "returning" with -- [1..10]. -- --
--   >>> flip runState 0 $ take 10 <$> streamAuto (arrM (modify . (+)) *> id) [1..]
--   ([1,2,3,4,5,6,7,8,9,10], .... (never terminates)
--   
-- -- This will immediately return the "result", and you can bind to the -- result with `(>>=)`, but it'll never return a "final state", -- because the final state involves executing all of the modifys. -- -- In other words, we stream values, not effects. You would -- analyze this behavior the same way you would look at something like -- mapM. -- -- If you want to stream effects, you can use streamAutoEffects or -- toEffectStream, and use an effects streaming library like -- pipes (or anything with ListT)...this will give the -- proper streaming of effects with resource handling, handling infinite -- streams in finite space with finite effects, etc. streamAuto :: Monad m => Auto m a b -> [a] -> m [b] -- | Stream an Auto' over a list, returning the list of results. -- Does this lazily, so this should work fine with (and is actually -- somewhat designed for) infinite lists. -- -- Note that conceptually this turns an Auto' a b into an -- [a] -> [b] -- --
--   >>> streamAuto' (arr (+3)) [1..10]
--   [4,5,6,7,8,9,10,11,12,13]
--   
--   >>> streamAuto' (sumFrom 0) [1..5]
--   [1,3,6,10,15]
--   
--   >>> streamAuto' (productFrom 1) . streamAuto' (sumFrom 0) $ [1..5]
--   [1,3,18,180,2700]
--   
--   >>> streamAuto' (productFrom 1 . sumFrom 0) $ [1..5]
--   [1,3,18,180,2700]
--   
--   >>> streamAuto' id [1..5]
--   [1,2,3,4,5]
--   
streamAuto' :: Auto' a b -> [a] -> [b] -- | Streams the Auto over a list of inputs; that is, "unwraps" the -- [a] -> m [b] inside. Streaming is done in the context of -- the underlying monad; when done consuming the list, the result is the -- list of outputs updated/next Auto in the context of the -- underlying monad. -- -- Basically just steps the Auto by feeding in every item in the -- list and pops out the list of results and the updated/next -- Auto, monadically chaining the steppings. -- -- See overList' for a simpler example; the following example uses -- effects from IO to demonstrate the monadic features of -- overList. -- --
--   >>> let a = arrM print *> sumFrom 0 :: Auto IO Int Int
--   
--   >>> (ys, a') <- overList a [1..5]
--   1    -- IO effects
--   2
--   3
--   4
--   5
--   
--   >>> ys
--   [1,3,6,10,15]
--   
--   >>> (ys', _) <- overList a' [11..15]
--   11   -- IO effects
--   12
--   13
--   14
--   15
--   
--   >>> ys'
--   [26,38,51,65,80]
--   
-- -- a is like sumFrom 0, except at every step, -- prints the input item to stdout as a side-effect. Note that in -- executing we get the updated a', which ends up with an -- accumulator of 15. Now, when we stream a', we pick up were we -- left off (from 15) on the results. overList :: Monad m => Auto m a b -> [a] -> m ([b], Auto m a b) -- | Streams an Auto' over a list of inputs; that is, "unwraps" the -- [a] -> [b] inside. When done comsuming the list, returns -- the outputs and the updated/next Auto'. -- --
--   >>> let (ys, updatedSummer) = overList' (sumFrom 0) [1..5]
--   
--   >>> ys
--   [1, 3, 6, 10, 15]
--   
--   >>> let (ys', _) = streamAuto' updatedSummer [1..5]
--   
--   >>> ys'
--   [16, 18, 21, 25, 30]
--   
-- -- If you wanted to stream over an infinite list then you don't care -- about the Auto' at the end, and probably want -- streamAuto'. overList' :: Auto' a b -> [a] -> ([b], Auto' a b) -- | Like overList, but "streams" the Auto over all elements -- of any Traversable, returning the final updated Auto. overTraversable :: (Monad m, Traversable t) => Auto m a b -> t a -> m (t b, Auto m a b) -- | Like overList', but "streams" the Auto' over all -- elements of any Traversable', returning the final updated -- Auto'. overTraversable' :: Traversable t => Auto' a b -> t a -> (t b, Auto' a b) -- | Streams (in the context of the underlying monad) the given Auto -- with a stream of constant values as input, a given number of times. -- After the given number of inputs, returns the list of results and the -- next/updated Auto, in the context of the underlying monad. -- --
--   stepAutoN n a0 x = overList a0 (replicate n x)
--   
-- -- See stepAutoN' for a simpler example; here is one taking -- advantage of monadic effects: -- --
--   >>> let a = arrM print *> sumFrom 0 :: Auto IO Int Int
--   
--   >>> (ys, a') <- stepAutoN 5 a 3
--   3                -- IO effects
--   3
--   3
--   3
--   3
--   
--   >>> ys
--   [3,6,9,12,15]    -- the result
--   
--   >>> (ys'', _) <- stepAutoN 5 a' 5
--   5                -- IO effects
--   5
--   5
--   5
--   5
--   
--   >>> ys''
--   [20,25,30,35,50] -- the result
--   
-- -- a here is like sumFrom 0, except at every -- step, prints the input item to stdout as a side-effect. stepAutoN :: Monad m => Int -> Auto m a b -> a -> m ([b], Auto m a b) -- | Streams the given Auto' with a stream of constant values as -- input, a given number of times. After the given number of inputs, -- returns the list of results and the next/updated Auto. -- --
--   stepAutoN' n a0 x = overList' a0 (replicate n x)
--   
-- --
--   >>> let (ys, a') = stepAutoN' 5 (sumFrom 0) 3
--   
--   >>> ys
--   [3,6,9,12,15]
--   
--   >>> let (ys', _) = stepAutoN' 5 a' 5
--   
--   >>> ys'
--   [20,25,30,35,40]
--   
stepAutoN' :: Int -> Auto' a b -> a -> ([b], Auto' a b) -- | Streams (in the context of the underlying monad) the given Auto -- with a stream of constant values as input, a given number of times. -- After the given number of inputs, returns the list of results in the -- context of the underlying monad. -- -- Like stepAutoN, but drops the "next Auto". Only returns -- the list of results. -- --
--   >>> let a = arrM print *> sumFrom 0 :: Auto IO Int Int
--   
--   >>> ys <- evalAutoN 5 a 3
--   3                -- IO effects
--   3
--   3
--   3
--   3
--   
--   >>> ys
--   [3,6,9,12,15]    -- the result
--   
-- -- a here is like sumFrom 0, except at every -- step, prints the input item to stdout as a side-effect. evalAutoN :: Monad m => Int -> Auto m a b -> a -> m [b] -- | Streams the given Auto' with a stream of constant values as -- input, a given number of times. After the given number of inputs, -- returns the list of results and the next/updated Auto. -- -- Like stepAutoN', but drops the "next Auto'". Only -- returns the list of results. -- --
--   >>> evalAutoN' 5 (sumFrom 0) 3
--   [3,6,9,12,15]
--   
evalAutoN' :: Int -> Auto' a b -> a -> [b] -- | Run an Auto' "interactively". Every step grab a string from -- stdin, and feed it to the Interval'. If the Interval' is -- "off", ends the session; if it is "on", then prints the output value -- to stdout and repeat all over again. -- -- If your Auto outputs something other than a String, you -- can use fmap to transform the output into a String -- en-route (like fmap show). -- -- If your Auto takes in something other than a String, you -- can lmap a function to convert the input String to -- whatever intput your Auto expects. -- -- You can use duringRead or bindRead if you have an -- Auto' or Interval' that takes something readable, -- to chug along until you find something non-readable; there's also -- interactRS which handles most of that for you. -- -- Outputs the final Interval' when the interaction terminates. interactAuto :: Interval' String String -> IO (Interval' String String) -- | Like interact, but instead of taking Interval' -- String String, takes any Interval' a -- b as long as a is Read and b is -- Show. -- -- Will "stop" if either (1) the input is not read-able or (2) the -- Interval' turns off. -- -- Outputs the final Auto' when the interaction terminates. interactRS :: (Read a, Show b) => Interval' a b -> IO (Interval' String String) -- | Like interact, but much more general. You can run it with an -- Auto of any underlying Monad, as long as you provide the -- natural transformation from that Monad to IO. -- -- The Auto can any Maybe b; you have to provide a -- function to "handle" it yourself; a b -> IO -- Bool. You can print the result, or write the result to a -- file, etc.; the Bool parameter determines whether or not to -- "continue running", or to stop and return the final updated -- Auto. interactM :: Monad m => (forall c. m c -> IO c) -> (b -> IO Bool) -> Auto m String b -> IO (Auto m String b) -- | Turn an Auto that takes a "readable" a and outputs a -- b into an Auto that takes a String and outputs -- a Maybe b. When the String is successfuly -- readable as the a, it steps the Auto and outputs a -- succesful Just result; when it isn't, it outputs a -- Nothing on that step. -- --
--   >>> let a0 = duringRead (accum (+) (0 :: Int))
--   
--   >>> let (y1, a1) = stepAuto' a0 "12"
--   
--   >>> y1
--   Just 12
--   
--   >>> let (y2, a2) = stepAuto' a1 "orange"
--   
--   >>> y2
--   Nothing
--   
--   >>> let (y3, _ ) = stepAuto' a2 "4"
--   
--   >>> y3
--   Just 16
--   
-- -- See interact for neat use cases. duringRead :: (Monad m, Read a) => Auto m a b -> Interval m String b -- | Like duringRead, but the original Auto would output a -- Maybe b instead of a b. Returns -- Nothing if either the String fails to parse or if the -- original Auto returned Nothing; returns Just if -- the String parses and the original Auto returned -- Just. -- -- See interact for neat use cases. bindRead :: (Monad m, Read a) => Interval m a b -> Interval m String b -- | Heavy duty abstraction for "self running" an Auto. Give a -- starting input action, a (possibly side-effecting) function from an -- output to the next input to feed in, and the Auto, and you get -- a feedback loop that constantly feeds back in the result of the -- function applied to the previous output. Stops when the "next -- input" function returns Nothing. -- -- Note that the none of the results are actually returned from the loop. -- Instead, if you want to process the results, they must be utilized in -- the "side-effects' of the "next input" function. (ie, a write to a -- file, or an accumulation to a state). run :: Monad m => m a -> (b -> m (Maybe a)) -> Auto m a b -> m (Auto m a b) -- | A generalized version of run where the Monad you are -- "running" the Auto in is different than the Monad -- underneath the Auto. You just need to provide the natural -- transformation. runM :: (Monad m, Monad m') => (forall c. m' c -> m c) -> m a -> (b -> m (Maybe a)) -> Auto m' a b -> m (Auto m' a b) -- | Runs the Auto' in IO with inputs read from a Chan queue, -- from Control.Concurrency.Chan. It'll block until the -- Chan has a new input, run the Auto with the received -- input, process the output with the given handling function, and start -- over if the handling function returns True. runOnChan :: (b -> IO Bool) -> Chan a -> Auto' a b -> IO (Auto' a b) -- | A generalized version of runOnChan that can run on any -- Auto m; all that is required is a natural -- transformation from the underyling Monad m to -- IO. runOnChanM :: Monad m => (forall c. m c -> IO c) -> (b -> IO Bool) -> Chan a -> Auto m a b -> IO (Auto m a b) -- | Turns an Auto m' a b with a list of inputs into a "ListT -- compatible effectful stream", as described at -- http://www.haskellforall.com/2014/11/how-to-build-library-agnostic-streaming.html -- -- Any library that offers a "ListT" type can use this -- result...and usually turn it into an effectful stream. -- -- For example, the pipes library offers runListT so you -- can run this, running the Auto over the input list, all with -- the effect stream manipulation tools and resource handling of -- pipes. -- -- This is useful because auto, the library, mainly provides tools -- for working with transformers for value streams, and not effect -- streams or streams of effects. Using this, you can potentially have -- the best of both worlds. streamAutoEffects :: (Monad m, MonadTrans t, MonadPlus (t m), Monad m') => (forall c. m' c -> m c) -> [a] -> Auto m' a b -> t m b -- | Turns an Auto m' a b and an "input producer" m a -- into a "ListT compatible effectful stream", as described at -- http://www.haskellforall.com/2014/11/how-to-build-library-agnostic-streaming.html -- -- Any library that offers a "ListT" type can use this -- result...and usually turn it into an effectful stream. -- -- For example, the pipes library offers runListT so you -- can run this, constantly pulling out as from the stream using -- the m a, feeding it in, and moving forward, all with the -- effect stream manipulation tools and resource handling of -- pipes. -- -- This is useful because auto, the library, mainly provides tools -- for working with transformers for value streams, and not effect -- streams or streams of effects. Using this, you can potentially have -- the best of both worlds. toEffectStream :: (Monad m, MonadTrans t, MonadPlus (t m), Monad m') => (forall c. m' c -> m c) -> m a -> Auto m' a b -> t m b -- | This module provides tools for working with the automatically derived -- serializability and resumability of Autos. The first half -- contains boring wrappers around encoding and decoding to and from -- binary, filepaths on disk, etc. -- -- The second half contains Auto transformers that "imbue" an -- Auto with IO serialization abilities. Note that these all -- require an underlying Monad that is an instance of -- MonadIO. -- -- You have "identity-like" transformers that take an Auto and -- spit it back out operationally unchanged...but every step, it might do -- some behind-the-scenes saving or re-load itself from disk when it is -- first stepped. Or you have some "trigger enhancers" that take normal -- Autos and give you the ability to "trigger" saving and loading -- events on the Auto using the Blip mechanisms and blip -- stream semantics from Control.Auto.Blip. -- -- Note that the entire Auto construct is a little bit awkward -- when it comes to performing IO effects --- it isn't exactly what they -- were designed for originally. Hooking on effects to stepping can be -- powerful, but as of now, not much has been looked into meaningful -- error handling when working with IO. If you have any experience with -- this and are willing to help, please feel free to send me an e-mail or -- open an issue on the issue tracker! module Control.Auto.Serialize -- | Returns a Put --- instructions (from Data.Serialize) on -- how to "freeze" the Auto, with its internal state, and save it -- to a binary encoding. It can later be reloaded and "resumed" by -- 'resumeAuto'/'decodeAuto'. saveAuto :: Auto m a b -> Put -- | Returns a Get from an Auto --- instructions (from -- Data.Serialize) on taking a ByteString and "restoring" the -- originally saved Auto, in the originally saved state. resumeAuto :: Auto m a b -> Get (Auto m a b) -- | Encode an Auto and its internal state into a ByteString. encodeAuto :: Auto m a b -> ByteString -- | Resume an Auto from its ByteString serialization, -- giving a Left if the deserialization is not possible. decodeAuto :: Auto m a b -> ByteString -> Either String (Auto m a b) -- | Given a FilePath and an Auto, serialize and freeze the -- state of the Auto as binary to that FilePath. writeAuto :: FilePath -> Auto m a b -> IO () -- | Give a FilePath and an Auto, and readAuto will -- attempt to resume the saved state of the Auto from disk, -- reading from the given FilePath. Will return Left upon a -- decoding error, with the error, and Right if the decoding is -- succesful. readAuto :: FilePath -> Auto m a b -> IO (Either String (Auto m a b)) -- | Like readAuto, but will return the original Auto -- (instead of a resumed one) if the file does not exist. -- -- Useful if you want to "resume an Auto" "if there is" a save -- state, or just use it as-is if there isn't. readAutoDef :: FilePath -> Auto m a b -> IO (Either String (Auto m a b)) -- | Transforms the given Auto into an Auto that -- constantly saves its state to the given FilePath at every -- "step". Requires an underlying MonadIO. -- -- Note that (unless the Auto depends on IO), the resulting -- Auto is meant to be operationally identical in its -- inputs/outputs to the original one. saving :: MonadIO m => FilePath -> Auto m a b -> Auto m a b -- | Like loading, except silently suppresses all I/O and decoding -- errors; if there are errors, it returns back the given Auto -- as-is. -- -- Useful for when you aren't sure the save state is on disk or not yet, -- and want to resume it only in the case that it is. loading' :: MonadIO m => FilePath -> Auto m a b -> Auto m a b -- | Transforms the given Auto into an Auto that, when -- you first try to run or step it, "loads" itself from disk at -- the given FilePath. -- -- Will throw a runtime exception on either an I/O error or a decoding -- error. -- -- Note that (unless the Auto depends on IO), the resulting -- Auto is meant to be operationally identical in its -- inputs/outputs to the fast-forwarded original Auto. loading :: MonadIO m => FilePath -> Auto m a b -> Auto m a b -- | Like serializing, except suppresses all I/O and decoding -- errors. -- -- Useful in the case that when the Auto is first run and there is -- no save state yet on disk (or the save state is corrupted), it'll -- "start a new one"; if there is one, it'll load it automatically. Then, -- on every further step in both cases, it'll update the save state. serializing' :: MonadIO m => FilePath -> Auto m a b -> Auto m a b -- | A combination of saving and loading. When the -- Auto is first run, it loads the save state from the given -- FilePath and fast forwards it. Then, subsequently, it updates -- the save state on disk on every step. serializing :: MonadIO m => FilePath -> Auto m a b -> Auto m a b -- | Takes an Auto and basically "wraps" it so that you can trigger -- saves with a blip stream. -- -- For example, we can take sumFrom 0: -- --
--   saveOnB (sumFrom 0) :: Auto IO (Int, Blip FilePath) Int
--   
-- -- It'll behave just like sumFrom 0 (with the input you -- pass in the first field of the tuple)...and whenever the blip stream -- (the second field of the input tuple) emits, it'll save the state of -- sumFrom 0 to disk at the given FilePath. -- -- Contrast to saveFromB, where the Auto itself can trigger -- saves; in this one, saves are triggered "externally". -- -- Might be useful in similar situations as saveFromB, except if -- you want to trigger the save externally. saveOnB :: MonadIO m => Auto m a b -> Auto m (a, Blip FilePath) b -- | Like loadOnB, except silently ignores errors. When a load is -- requested, but there is an IO or parse error, the loading is skipped. loadOnB' :: MonadIO m => Auto m a b -> Auto m (a, Blip FilePath) b -- | Takes an Auto and basically "wraps" it so that you can trigger -- loads/resumes from a file with a blip stream. -- -- For example, we can take sumFrom 0: -- --
--   loadOnB (sumFrom 0) :: Auto IO (Int, Blip FilePath) Int
--   
-- -- It'll behave just like sumFrom 0 (with the input you -- pass in the first field of the tiple)...and whenever the blip stream -- (the second field of the input tuple) emits, it'll "reset" and -- "reload" the sumFrom 0 from the FilePath on -- disk. -- -- Will throw a runtime exception if there is an IO error or a parse -- error. -- -- Contrast to loadFromB, where the Auto itself can trigger -- reloads/resets; in this one, the loads are triggered "externally". -- -- Might be useful in similar situations as loadFromB, except if -- you want to trigger the loading externally. loadOnB :: MonadIO m => Auto m a b -> Auto m (a, Blip FilePath) b -- | Takes an Auto that produces a blip stream with a -- FilePath and a value, and turns it into an Auto that, -- outwardly, produces just the value. -- -- Whenever the output blip stream emits, it automatically serializes and -- saves the state of the Auto to the emitted FilePath. -- -- In practice, this allows any Auto to basically control when it -- wants to "save", by providing a blip stream. -- -- The following is an alternative implementation of saving, -- except saving every two steps instead of every step: -- --
--   saving2 fp a = saveFromB (a &&& (every 2 . pure fp))
--   
-- -- Or, in proc notation: -- --
--   saving2 fp a = saveFromB $ proc x -> do
--       y <- a       -< x
--       b <- every 2 -< fp
--       id -< (y, b)
--   
-- -- (Recall that every n is the Auto that emits -- the received value every n steps) -- -- In useful real-world cases, you can have the Auto decide -- whether or not to save itself based on its input. Like, for example, -- when it detects a certain user command, or when the user has reached a -- given location. -- -- The following takes a FilePath and an Auto (a), -- and turns it into an Auto that "saves" whenever a -- crosses over from positive to negative. -- --
--   saveOnNegative fp a = saveFromB $ proc x -> do
--       y       <- a            -< x
--       saveNow <- became (< 0) -< y
--       id       -< (y, fp <$ saveNow)
--   
-- -- Contrast to saveOnB, where the saves are triggered by outside -- input. In this case, the saves are triggered by the Auto to be -- saved itself. saveFromB :: MonadIO m => Auto m a (b, Blip FilePath) -> Auto m a b -- | Like loadFromB, except silently ignores errors. When a load is -- requested, but there is an IO or parse error, the loading is skipped. loadFromB' :: MonadIO m => Auto m a (b, Blip FilePath) -> Auto m a b -- | Takes an Auto that outputs a b and a blip stream of -- FilePaths and returns an Auto that ouputs only that -- b stream...but every time the blip stream emits, it -- "resets/loads" itself from that FilePath. -- -- The following is a re-implementation of loading...except -- delayed by one (the second step that is run is the first "resumed" -- step). -- --
--   loading2 fp a = loadFromB $ proc x -> do
--       y       <- a           -< x
--       loadNow <- immediately -< fp
--       id       -< (y, loadNow)
--   
-- -- (the blip stream emits only once, immediately, to re-load). -- -- In the real world, you could have the Auto decide to reset or -- resume itself based on a user command: -- --
--   loadFrom = loadFromB $ proc x -> do
--       steps  <- count -< ()
--       toLoad <- case words x of
--                     ("load":fp:_) -> do
--                         immediately -< fp
--                     _             -> do
--                         never       -< ()
--       id      -< (steps, toLoad)
--   
-- -- This will throw a runtime error on an IO exception or parsing error. loadFromB :: MonadIO m => Auto m a (b, Blip FilePath) -> Auto m a b -- | This module contains various Auto transformers for manipulating -- the flow of time/stepping rate of an Auto. -- -- Many of these are Auto "transformers", meaning that they take -- in an Auto and return a transformed Auto, with new -- stepping behavior. -- -- For example, there is accelerate: -- --
--   accelerate :: Monad m => Int -> Auto m a b -> Auto m a [b]
--   
-- -- accelerate n turns an Auto into an Auto -- that "steps itself" n times for every single input/step. The -- result is a list of the results of each single step. -- -- There are also various Autos for observing the passage of time -- (count) and actiong as a "delay" or a way to access the -- previously stepped values of an Auto. module Control.Auto.Time -- | A simple Auto that ignores all input; its output stream counts -- upwards from zero. -- --
--   >>> take 10 . streamAuto' count $ repeat ()
--   [0,1,2,3,4,5,6,7,8,9]
--   
count :: (Serialize b, Num b) => Auto m a b -- | A non-resuming/non-serializing version of count. count_ :: Num b => Auto m a b -- | When first asked for output, "primes" the Auto first by -- streaming it with all of the given inputs first before processing the -- first input. Aterwards, behaves like normal. -- --
--   >>> streamAuto' (priming [1,2,3] (sumFrom 0)) [1..10]
--   [7,9,12,16,21,27,34,42,51,61]
--   
-- -- The Auto behaves as if it had already "processed" the -- [1,2,3], resulting in an accumulator of 6, before it starts -- taking in any input. -- -- Normally this would be silly with an Auto', because the above -- is the same as: -- --
--   >>> let (_, a) = overList' (sumFrom 0) [1,2,3]
--   
--   >>> streamAuto' a [1..10]
--   [7,9,12,16,21,27,34,42,51,61]
--   
-- -- This becomes somewhat more useful when you have "monadic" -- Autos, and want to defer the execution until during normal -- stepping: -- --
--   >>> _ <- streamAuto (priming [1,2,3] (arrM print)) [10,11,12]
--   1    -- IO effects
--   2
--   3
--   10
--   11
--   12
--   
priming :: Monad m => [a] -> Auto m a b -> Auto m a b -- | An Auto that returns the last value received by it. Given an -- "initial value" to output first. -- -- From the signal processing world, this is known as the "lag operator" -- L. -- -- This is (potentially) a very dangerous Auto, because its -- usage and its very existence opens the door to breaking -- denotative/declarative style and devolving into imperative style -- coding. However, when used where it is supposed to be used, it is more -- or less invaluable, and will be an essential part of many programs. -- -- Its main usage is for dealing with recursive bindings. If you ever are -- laying out recursive bindings in a high-level/denotative way, you need -- to have at least one value be able to have a "initial output" without -- depending on anything else. lastVal and delay allow you -- to do this. -- -- See the recursive example for more information on the -- appropriate usage of lastVal and delay. -- --
--   >>> streamAuto' (lastVal 100) [1..10]
--   [100,1,2,3,4,5,6,7,8,9]
--   
lastVal :: Serialize a => a -> Auto m a a -- | The non-resuming/non-serializing version of lastVal. lastVal_ :: a -> Auto m a a -- | Like arr, but applies the function to the previous value -- of the input, instead of the current value. Used for the same purposes -- as lastVal: to manage recursive bindings. -- -- Warning: Don't use this to do imperative programming! -- --
--   arrD id == lastVal
--   
-- --
--   >>> streamAuto' (arrD negate 100) [1..10]
--   [100,-1,-2,-3,-4,-5,-6,-7,-8,-9]
--   
arrD :: Serialize b => (a -> b) -> b -> Auto m a b -- | The non-resuming/non-serializing version of arrD. arrD_ :: Serialize b => (a -> b) -> b -> Auto m a b -- | An alias for lastVal; used in contexts where "delay" is more a -- meaningful description than "last value". All of the warnings for -- lastVal still apply, so you should probably read it if you -- haven't :) delay :: Serialize a => a -> Auto m a a -- | The non-resuming/non-serializing version of delay. delay_ :: a -> Auto m a a -- | Like delay, except has as many "initial values" as the input -- list. Outputs every item in the input list in order before returning -- the first received value. -- --
--   delayList [y0] = delay y0
--   
-- --
--   >>> streamAuto' (delayList [3,5,7,11]) [1..10]
--   [3,5,7,11,1,2,3,4,5,6]
--   
delayList :: (Serialize a, Monad m) => [a] -> Auto m a a -- | The non-resuming/non-serializing version of delayList. delayList_ :: Monad m => [a] -> Auto m a a -- | Like delay, except delays the desired number of steps with the -- same initial output value. -- --
--   delayN n x0 = delayList (replicate n x0)
--   
-- --
--   delayN 1 x0 = delay x0
--   
-- --
--   >>> streamAuto' (delayN 3 0) [1..10]
--   [0,0,0,1,2,3,4,5,6,7]
--   
delayN :: (Serialize a, Monad m) => Int -> a -> Auto m a a -- | The non-resuming/non-serializing version of delayN delayN_ :: Monad m => Int -> a -> Auto m a a -- | "stretch" an Auto out, slowing time. stretch n -- a will take one input, repeat the same output n times -- (ignoring input), and then take another. It ignores all inputs in -- between. -- --
--   >>> let a = stretch 2 (sumFrom 0)
--   
--   >>> streamAuto' a [1,8,5,4,3,7,2,0]
--      [1,1,6,6,9,9,11,11]
--   -- [1,_,5,_,3,_,2 ,_ ] <-- the inputs
--   
stretch :: (Serialize b, Monad m) => Int -> Auto m a b -> Auto m a b -- | The non-resuming/non-serializing version of stretch. stretch_ :: Monad m => Int -> Auto m a b -> Auto m a b -- | Like stretch, but instead of holding the the "stretched" -- outputs, outputs a blip stream that emits every time the stretched -- Auto "progresses" (every n ticks) -- -- See stretch for more information. -- --
--   >>> let a = stretchB 2 (accum (+) 0)
--   
--   >>> streamAuto' a [1,8,5,4,3,7,2,0]
--   [Blip 1, NoBlip, Blip 6, NoBlip, Blip 9, NoBlip, Blip 11, NoBlip]
--   
stretchB :: Monad m => Int -> Auto m a b -> Auto m a (Blip b) -- | A more general version of stretch; instead of just ignoring and -- dropping the "stretched/skipped intervals", accumulate all of them up -- with the given accumulating function and then "step" them all at once -- on every nth tick. Also, stead of returning exactly the same -- output every time over the stretched interval, output a function of -- the original output during the stretched intervals. -- --
--   >>> streamAuto' (sumFrom 0) [1..10]
--   [1, 3, 6, 10, 15, 21, 28, 36, 45 ,55]
--   
--   >>> streamAuto' (stretchAccumBy (+) negate 4 (sumFrom 0)) [1..10]
--   [1,-1,-1, -1, 15,-15,-15,-15, 45,-45]
--   
-- -- Here, instead of feeding in a number every step, it "accumulates" all -- of the inputs using + and "blasts them into" -- sumFrom 0 every 4 steps. In between the blasts, it -- outputs the negated last seen result. -- -- You can recover the behavior of stretch with -- stretchAccumBy (flip const) id. stretchAccumBy :: (Serialize a, Serialize b, Monad m) => (a -> a -> a) -> (b -> b) -> Int -> Auto m a b -> Auto m a b -- | The non-serialized/non-resuming version of stretchAccumBy. stretchAccumBy_ :: Monad m => (a -> a -> a) -> (b -> b) -> Int -> Auto m a b -> Auto m a b -- | accelerate n a turns an Auto a into an -- "accelerated" Auto, where every input is fed into the -- Auto n times. All of the results are collected in the -- output. -- -- The same input is fed repeatedly n times. -- --
--   >>> streamAuto' (accelerate 3 (sumFrom 0)) [2,3,4]
--   [[2,4,6],[9,12,15],[19,23,27]]
--   -- ^adding 2s  ^adding 3s ^adding 4s
--   
accelerate :: Monad m => Int -> Auto m a b -> Auto m a [b] -- | accelerateWith xd n a is like accelerate n -- a, except instead of feeding in the input n times, it -- feeds the input in once and repeats the "filler" xd for the -- rest of the accelerating period. -- --
--   >>> streamAuto' (accelerateWith (-1) 3 (sumFrom 0)) [1,10,100]
--   [[1,0,-1],[9,8,7],[107,106,105]]
--   -- ^ feed in 1 once and -1 twice
--   --          ^ feed in 10 once and -1 twice
--   --                  ^ feed in 100 once and -1 twice
--   
accelerateWith :: Monad m => a -> Int -> Auto m a b -> Auto m a [b] -- | Accelerates the Auto, so instead of taking an a -- and returning a b, it takes a list of a, "streams" -- the Auto over each one, and returns a list of b -- results. -- -- For example, if you normally feed sumFrom 0 a 1, -- then a 2, then a 3, you'd get a 1, then a 3, then a 6. But if you feed -- accelOverList (sumFrom 0) a [1,2], -- you'd get a [1,3], and if you fed it a [3] after, -- you'd get a [6]. -- -- Turns a [a] -> [b] into an [[a]] -> [[b]]; if -- you "chunk up" the input stream as into chunks of input to -- feed all at once, the outputs b will be chunked up the same -- way. -- --
--   >>> streamAuto' (sumFrom 0) [1,2,3,4,5,6,7,8]
--   [1,3,6,10,15,21,28,36]
--   
--   >>> streamAuto' (accelOverList (sumFrom 0)) [[1,2],[],[3,4,5],[6],[7,8]]
--   [[1,3],[],[6,10,15],[21],[28,36]]
--   
-- -- Mostly useful if you want to feed an Auto multiple inputs in -- the same step. Note that if you always feed in singleton lists (lists -- with one item), you'll more or less get the same behavior as normal. accelOverList :: Monad m => Auto m a b -> Auto m [a] [b] -- | Takes an Auto that produces (b, Blip c), and -- turns it into an Auto that produces ([b], c). -- -- Basically, the new Auto "squishes together" the periods of -- output between each time the blip stream emits. All outputs between -- each emitted value are accumulated and returned in the resulting -- [b]. -- -- It "does this" in the same manner as accelerateWith and -- fastForward: first feed the input, then step repeatedly with -- the default input value. -- --
--   >>> let a :: Auto' Int (Int, Blip String)
--           a = proc i -> do
--                   sums <- sumFrom 0 -< i
--                   blp  <- every 3   -< i     -- emits every 3 ticks.
--                   id    -< (sums, sums <& blp) -- replace emitted value
--                                                -- with the running sum
--   
--   >>> let skipA :: Auto' Int ([Int], String)
--           skipA = skipTo (-1) a
--   
--   >>> let (res1, skipA') = stepAuto' skipA 8
--   
--   >>> res1
--   ([8,7,6], 6)     -- fed 8 first, then (-1) repeatedly
--   
--   >>> let (res2, _     ) = evalAuto skipA' 5
--   
--   >>> res2
--   ([11,10,9], 9)   -- fed 5 first, then (-1) repeatedly
--   
-- -- If the blip stream never emits then stepping this and getting the -- result or the next/updated Auto never terminates...so watch -- out! skipTo :: Monad m => a -> Auto m a (b, Blip c) -> Auto m a ([b], c) -- | Turns an Interval m a b into an Auto m a -- b --- that is, an Auto m a (Maybe b) into an -- Auto m a b. -- -- It does this by "skipping over" all "off"/Nothing input. When -- the result "should" be a Nothing, it re-runs the -- Interval over and over again with the given default input until -- the Auto turns back "on" again (outputs a Just). -- -- If the Interval reaches a point where it will never be "on" -- again, stepping this and getting the result or the next/updated -- Auto won't terminate...so watch out! -- --
--   >>> let a1 = offFor 3 . sumFrom 0
--   
--   >>> streamAuto' a1 [1..10]
--   [Nothing, Nothing, Nothing, Just 10, Just 15, Just 21]
--   
--   >>> streamAuto' (fastForward 0 a1) [1..6]
--   [1,3,6,10,15,21]
--   
--   >>> streamAuto' (fastForward (-10) a1) [1..6]
--   [-29,-27,-24,-20,-15,-9]
--   
-- -- In that last example, the first input is 1, then it inputs (-10) until -- it is "on"/Just again (on the fourth step). Then continues -- imputing 2, 3, 4 etc. fastForward :: Monad m => a -> Interval m a b -> Auto m a b -- | Same behavior as fastForward, except accumulates all of the -- Left c outputs in a list. fastForwardEither :: Monad m => a -> Auto m a (Either c b) -> Auto m a (b, [c]) -- | The Autos in this module are all dedicated to managing and -- working with (possibly dynamic) "collections" of Autos: an -- Auto where the output stream is typically many output -- streams collected from running many input streams through many -- internal Autos. -- -- Particularly useful because a lot of these allow you to add or take -- away these "channels of inputs" (or "internal Autos") -- dynamically; so, useful for collections that can be added to or -- deleted from, like monsters on a map. -- -- These multiplex, merge, or collect input streams through many -- Autos and output the multiplexed, merged, or collected output -- streams. -- -- A lot of these Autos take advantaage Interval semantics -- (Maybe for continuous on/off periods) to signal when they want -- to be removed or turned off. -- -- For these, the best way to learn them is probably by seeing examples. -- -- If there is a time when you might want collections of things that can -- be added to or removed from dynamically, this might be what you are -- looking for. -- -- These collections are indispensible for coding real applications; many -- examples of them in use are available in the auto-examples -- project! See those projects for "real-world" guides. module Control.Auto.Collection -- | Give a list of Auto m a b and get back an -- Auto m [a] [b] --- take a list of a's and -- feed them to each of the Autos, and collects their output -- b's. -- -- If the input list doesn't have enough items to give to all of the -- Autos wrapped, then use the given default value. Any extra -- items in the input list are ignored. -- -- For an example, we're going to make a list of Autos that output -- a running sum of all of their inputs, but each starting at a different -- beginning value: -- --
--   summerList :: [Auto' Int Int]
--   summerList = [sumFrom 0, sumFrom 10, sumFrom 20, sumFrom 30]
--   
-- -- Then, let's throw it into zipAuto with a sensible default -- value, 0: -- --
--   summings0 :: Auto' [Int] [Int]
--   summings0 = zipAuto 0 summerList
--   
-- -- Now let's try it out! -- --
--   >>> let (r1, summings1) = stepAuto' summings0 [1,2,3,4]
--   
--   >>> r1
--   [ 1, 12, 23, 34]
--   
--   >>> let (r2, summings2) = stepAuto' summings1 [5,5]
--   
--   >>> r2
--   [ 6, 17, 23, 34]
--   
--   >>> let (r3, _        ) = stepAuto' summings2 [10,1,10,1,10000]
--   
--   >>> r3
--   [16, 18, 33, 35]
--   
zipAuto :: Monad m => a -> [Auto m a b] -> Auto m [a] [b] -- | Like zipAuto, but delay the input by one step. The first input -- to all of them is the "default" value, and after that, feeds in the -- input streams delayed by one. -- -- Let's try the example from zipAuto, except with dZipAuto -- instead: -- --
--   summerList :: [Auto' Int Int]
--   summerList = map sumFrom [0, 10, 20, 30]
--   
--   summings0 :: Auto' [Int] [Int]
--   summings0 = dZipAuto 0 summerList
--   
-- -- Trying it out: -- --
--   >>> let (r1, summings1) = stepAuto' summings0 [1,2,3,4]
--   
--   >>> r1
--   [ 0, 10, 20, 30]
--   
--   >>> let (r2, summings2) = stepAuto' summings1 [5,5]
--   
--   >>> r2
--   [ 1, 12, 23, 34]
--   
--   >>> let (r3, summings3) = stepAuto' summings2 [10,1,10,1,10000]
--   
--   >>> r3
--   [ 6, 17, 23, 34]
--   
--   >>> let (r4, _        ) = stepAuto' summings3 [100,100,100,100]
--   
--   >>> r4
--   [16, 18, 33, 35]
--   
dZipAuto :: (Serialize a, Monad m) => a -> [Auto m a b] -> Auto m [a] [b] -- | The non-serializing/non-resuming version of dZipAuto. dZipAuto_ :: Monad m => a -> [Auto m a b] -> Auto m [a] [b] -- | Takes a bunch of Autos that take streams streams, and turns -- them into one Auto that takes a bunch of blip streams and feeds -- them into each of the original Autos, in order. -- -- It's basically like zipAuto, except instead of taking in normal -- streams of values, it takes in blip streams of values. -- -- If the input streams ever number less than the number of Autos -- zipped, the other Autos are stepped assuming no emitted value. zipAutoB :: Monad m => [Auto m (Blip a) b] -> Auto m [Blip a] [b] -- | A delayed version of zipAutoB dZipAutoB :: (Serialize a, Monad m) => [Auto m (Blip a) b] -> Auto m [Blip a] [b] -- | The non-serializing/non-resuming version of dZipAutoB. dZipAutoB_ :: Monad m => [Auto m (Blip a) b] -> Auto m [Blip a] [b] -- | A dynamic box of Intervals. Takes a list of inputs to feed to -- each one, in the order that they were added. Also takes a blip stream, -- which emits with new Intervals to add to the box. -- -- Add new Intervals to the box however you want with the blip -- stream. -- -- As soon as an Interval turns "off", the Interval is -- removed from the box, and its output is silenced. -- -- The adding/removing aside, the routing of the inputs (the first field -- of the tuple) to the internal Autos and the outputs behaves the -- same as with zipAuto. -- -- This will be a pretty powerful collection if you ever imagine adding -- and destroying behaviors dynamically...like spawning new enemies, or -- something like that. -- -- Let's see an example...here we are going to be throwing a bunch of -- Autos that count to five and then die into our -- dynZip_...once every other step. -- --
--   -- count upwards, then die when you reach 5
--   countThenDie :: Interval' () Int
--   countThenDie = onFor 5 . iterator (+1) 1
--   
--   -- emit a new countThenDie every two steps
--   throwCounters :: Auto' () (Blip [Interval' () Int])
--   throwCounters = tagBlips [countThenDie] . every 2
--   
--   a :: Auto' () [Int]
--   a = proc _ -> do
--           newCounter <- throwCounters -< ()
--           dynZip_ ()  -< (repeat (), newCounter)
--   
-- --
--   >>> let (res, _) = stepAutoN' 15 a ()
--   
--   >>> res
--   [[], [1            ]
--      , [2,           ]
--      , [3, 1         ]
--      , [4, 2         ]
--      , [5, 3, 1      ]
--      , [   4, 2      ]
--      , [   5, 3, 1   ]
--      , [      4, 2   ]
--      , [      5, 3, 1]
--   ]
--   
-- -- This is a little unweildy, because Autos maybe disappearing out -- of the thing while you are trying to feed inputs into it. You might be -- feeding an input to an Auto...but one of the Autos -- before it on the list has disappeared, so it accidentally goes to the -- wrong one. -- -- Because of this, it is suggested that you use dynMap_, which -- allows you to "target" labeled Autos with your inputs. -- -- This Auto is inherently unserializable, but you can use -- dynZipF for more or less the same functionality, with -- serialization possible. It's only slightly less powerful...for all -- intents and purposes, you should be able to use both in the same -- situations. All of the examples here can be also done with -- dynZipF. dynZip_ :: Monad m => a -> Auto m ([a], Blip [Interval m a b]) [b] -- | Like dynZip_, but instead of taking in a blip stream of -- Intervals directly, takes in a blip stream of ks to -- trigger adding more Intervals to the "box", using the given -- k -> Interval m a b function to make the new -- Interval to add. -- -- Pretty much all of the power of dynZip_, but with -- serialization. -- -- See dynZip_ for examples and caveats. -- -- You could theoretically recover the behavior of dynZip_ with -- dynZipF id, if there wasn't a Serialize -- constraint on the k. dynZipF :: (Serialize k, Monad m) => (k -> Interval m a b) -> a -> Auto m ([a], Blip [k]) [b] -- | The non-serializing/non-resuming version of dynZipF. Well, you -- really might as well use dynZip_, which is more powerful...but -- maybe using this can inspire more disciplined usage. Also works as a -- drop-in replacement for dynZipF. dynZipF_ :: Monad m => (k -> Interval m a b) -> a -> Auto m ([a], Blip [k]) [b] -- | A dynamic box of Autos, indexed by an Int. Takes an -- IntMap of inputs to feed into their corresponding Autos, -- and collect all of the outputs into an output IntMap. -- -- Whenever any of the internal Autos return Nothing, they -- are removed from the collection. -- --
--   >>> import qualified Data.IntMap as IM
--   
--   >>> let dm0 :: Auto' (IM.IntMap Int) (IM.IntMap Int)
--           dm0 = proc x -> do
--                     initials <- immediately -< [ Just <$> sumFrom 0
--                                                , Just <$> sumFrom 10 ]
--                     newIs    <- every 3     -< [ Just <$> sumFrom 0  ]
--                     dynMap_ (-1) -< (x, initials `mergeL` newIs)
--   
--   >>> let (res1, dm1) = stepAuto' dm0 mempty
--   
--   >>> res1
--   fromList [(0, -1), (1, 9)]
--   
--   >>> let (res2, dm2) = stepAuto' dm1 (IM.fromList [(0,100),(1,50)])
--   
--   >>> res2
--   fromList [(0, 99), (1, 59)]
--   
--   >>> let (res3, dm3) = stepAuto' dm2 (IM.fromList [(0,10),(1,5)])
--   
--   >>> res3
--   fromList [(0, 109), (1, 64), (2, -1)]
--   
--   >>> let (res4, _  ) = stepAuto' dm3 (IM.fromList [(1,5),(2,5)])
--   
--   >>> res4
--   fromList [(0, 108), (1, 69), (2, 4)]
--   
-- -- One quirk is that every internal Auto is "stepped" at every -- step with the default input; gatherMany is a version of this -- where Autos that do not have a corresponding "input" are left -- unstepped, and their last output preserved in the aggregate output. As -- such, gatherMany might be seen more often. -- -- This Auto is inherently unserializable, but you can use -- dynMapF for more or less the same functionality, with -- serialization possible. It's only slightly less powerful...for all -- intents and purposes, you should be able to use both in the same -- situations. All of the examples here can be also done with -- dynMapF. dynMap_ :: Monad m => a -> Auto m (IntMap a, Blip [Interval m a b]) (IntMap b) -- | Like dynMap_, but instead of taking in a blip stream of -- Intervals directly, takes in a blip stream of ks to -- trigger adding more Intervals to the "box", using the given -- k -> Interval m a b function to make the new -- Interval to add. -- -- Pretty much all of the power of dynMap_, but with -- serialization. -- -- See dynMap_ for examples and use cases. -- -- You could theoretically recover the behavior of dynMap_ with -- dynMapF id, if there wasn't a Serialize -- constraint on the k. dynMapF :: (Serialize k, Monad m) => (k -> Interval m a b) -> a -> Auto m (IntMap a, Blip [k]) (IntMap b) -- | The non-serializing/non-resuming version of dynMapF. Well, you -- really might as well use dynMap_, which is more powerful...but -- maybe using this can inspire more disciplined usage. Also works as a -- drop-in replacement for dynMapF. dynMapF_ :: Monad m => (k -> Interval m a b) -> a -> Auto m (IntMap a, Blip [k]) (IntMap b) -- | Auto multiplexer. Stores a bunch of internal Autos -- indexed by a key. At every step, takes a key-input pair, feeds the -- input to the Auto stored at that key and outputs the output. -- -- If the key given does not yet have an Auto stored at that key, -- initializes a new Auto at that key by using the supplied -- function. -- -- Once initialized, these Autos are stored there forever. -- -- You can play around with some combinators from -- Control.Auto.Switch; for example, with resetOn, you -- can make Autos that "reset" themselves when given a certain -- input. switchOnF could be put to use here too in neat ways. -- --
--   >>> let mx0 = mux (\_ -> sumFrom 0)
--   
--   >>> let (res1, mx1) = stepAuto' mx0 ("hello", 5)
--   
--   >>> res1
--   5
--   
--   >>> let (res2, mx2) = stepAuto' mx1 ("world", 3)
--   
--   >>> res2
--   3
--   
--   >>> let (res3, mx3) = stepAuto' mx2 ("hello", 4)
--   
--   >>> res3
--   9
--   
--   >>> streamAuto' mx3 [("world", 2), ("foo", 6), ("foo", 1), ("hello", 2)]
--   [5, 6, 7, 11]
--   
mux :: (Serialize k, Ord k, Monad m) => (k -> Auto m a b) -> Auto m (k, a) b -- | The non-serializing/non-resuming version of mux. mux_ :: (Ord k, Monad m) => (k -> Auto m a b) -> Auto m (k, a) b -- | Like muxI, but holds Intervals 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) -> Auto m (k, a) (Maybe b) -- | The non-serializing/non-resuming version of muxI. muxI_ :: (Ord k, Monad m) => (k -> Interval m a b) -> Auto m (k, a) (Maybe b) -- | Auto multiplexer, like mux, except allows update/access -- of many Autos at a time. Instead of taking in a single -- key-value pair and outputting a single result, takes in an entire -- Map of key-value pairs and outputs a Map of key-result -- pairs. -- --
--   >>> import qualified Data.Map as M
--   
--   >>> let mx0 = mux (\_ -> sumFrom 0)
--   
--   >>> let (res1, mx1) = stepAuto' mx0 (M.fromList [ ("hello", 5)
--                                                   , ("world", 3) ])
--   
--   >>> res1
--   fromList [("hello", 5), ("world", 3)]
--   
--   >>> let (res2, mx2) = stepAuto' mx1 (M.fromList [ ("hello", 4)
--                                                   , ("foo"  , 7) ])
--   
--   >>> res2
--   fromList [("foo", 7), ("hello", 9)]
--   
--   >>> let (res3, _  ) = mx2 (M.fromList [("world", 3), ("foo", 1)])
--   
--   >>> res3
--   fromList [("foo", 8), ("world", 6)]
--   
-- -- See mux for more notes. muxMany :: (Serialize k, Ord k, Monad m) => (k -> Auto m a b) -> Auto m (Map k a) (Map k b) -- | The non-serializing/non-resuming version of muxMany. muxMany_ :: (Ord k, Monad m) => (k -> Auto m a b) -> Auto m (Map k a) (Map k b) -- | Like muxManyI, but holds Intervals instead. When any -- given Interval turns "off", it's removed from the collection. -- Only Intervals 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) -> Auto m (Map k a) (Map k b) -- | The non-serializing/non-resuming version of muxManyI. muxManyI_ :: (Ord k, Monad m) => (k -> Interval m a b) -> Auto m (Map k a) (Map k b) -- | Keeps an internal Map of Intervals and, at every step, -- the output is the last seen output of every Interval, indexed -- under the proper key. -- -- At every step, the input is a key-value pair; gather will feed -- that input value to the Interval under the proper key and -- update the output map with that new result. -- -- If the key offered the input is not yet a part of the collection, -- initializes it with the given function. -- -- Any Interval that turns "off" (outputs Nothing) from -- this will be immediately removed from the collection. If something for -- that key is received again, it will re-initialize it. -- --
--   >>> let sumUntil :: Interval' Int Int
--           sumUntil = proc x -> do
--                          sums <- sumFrom 0     -< x
--                          stop <- became (> 10) -< sums
--                          before -< (sums, stop)
--       -- (a running sum, "on" until the sum is greater than 10)
--   
--   >>> let gt0 = gather (\_ -> sumUntil)
--   
--   >>> let (res1, gt1) = stepAuto' gt0 ("hello", 5)
--   
--   >>> res1
--   fromList [("hello", 5)]
--   
--   >>> let (res2, gt2) = stepAuto' gt1 ("world", 7)
--   
--   >>> res2
--   fromList [("hello", 5), ("world", 7)]
--   
--   >>> let (res3, gt3) = stepAuto' gt2 ("foo", 4)
--   
--   >>> res3
--   fromList [("foo", 4), ("hello", 5), ("world", 7)]
--   
--   >>> let (res4, gt4) = stepAuto' gt3 ("world", 8)
--   
--   >>> res4
--   fromList [("foo", 4), ("hello", 5)]
--   
--   >>> streamAuto' gt4 [("world", 2),("bar", 9),("world", 6),("hello", 11)]
--   [ fromList [("foo", 4), ("hello", 5), ("world", 2)]
--   , fromList [("bar", 9), ("foo", 4), ("hello", 5), ("world", 2)]
--   , fromList [("bar", 9), ("foo", 4), ("hello", 5), ("world", 8)]
--   , fromList [("bar", 9), ("foo", 4), ("world", 8)]
--   ]
--   
-- -- In practice this ends up being a very common collection; see the -- auto-examples project for many examples! -- -- Because everything needs a key, you don't have the fancy -- "auto-generate new keys" feature of dynMap...however, you -- could always pull a new key from perBlip -- enumFromA or something. -- -- Like with mux, combinators from Control.Auto.Switch like -- resetOn and switchOnF are very useful here! gather :: (Ord k, Monad m, Serialize k, Serialize b) => (k -> Interval m a b) -> Auto m (k, a) (Map k b) -- | The non-serializing/non-resuming version of gather: -- -- Does serialize the actual Autos themselves; the -- Autos are all serialized and re-loaded/resumed when 'gather_ f' -- is resumed. -- -- Does not serialize the "last outputs", so resumed Autos -- that have not yet been re-run/accessed to get a fresh output are not -- represented in the output map at first. gather_ :: (Ord k, Monad m, Serialize k) => (k -> Interval m a b) -> Auto m (k, a) (Map k b) -- | The non-serializing/non-resuming vervsion of gather: -- -- Serializes neither the Autos themselves nor the "last outputs" -- --- essentially, serializes/resumes nothing. gather__ :: (Ord k, Monad m) => (k -> Interval m a b) -> Auto m (k, a) (Map k b) -- | Much like gather, except allows you to pass in multiple -- key-value pairs every step, to update multiple internal Autos. -- --
--   >>> import qualified Data.Map as M
--   
--   >>> let sumUntil :: Interval' Int Int
--           sumUntil = proc x -> do
--                          sums <- sumFrom 0     -< x
--                          stop <- became (> 10) -< sums
--                          before -< (sums, stop)
--       -- (a running sum, "on" until the sum is greater than 10)
--   
--   >>> let gm0 = gatherMany (\_ -> sumUntil)
--   
--   >>> let (res1, gm1) = stepAuto' gm0 (M.fromList [ ("hello", 5)
--                                                   , ("world", 7)
--                                                   ])
--   
--   >>> res1
--   fromList [("hello", 5), ("world", 7)]
--   
--   >>> let (res2, gm2) = stepAuto' gm1 (M.fromList [ ("foo", 4)
--                                                   , ("hello", 3)
--                                                   ])
--   
--   >>> res2
--   fromList [("foo", 4), ("hello", 8), ("world", 7)]
--   
--   >>> let (res3, gm3) = stepAuto' gm2 (M.fromList [ ("world", 8)
--                                                   , ("bar", 9)
--                                                   ])
--   
--   >>> res3
--   fromList [("bar", 9), ("foo", 4), ("hello", 8)]
--   
--   >>> let (res4, _  ) = stepAuto' gm3 (M.fromList [ ("world", 2)
--                                                   , ("bar", 10)
--                                                   ])
--   
--   >>> res4
--   fromList [("foo", 4), ("hello", 8), ("world", 2)]
--   
-- -- See gather for more notes. gatherMany :: (Ord k, Monad m, Serialize k, Serialize b) => (k -> Interval m a b) -> Auto m (Map k a) (Map k b) -- | The non-serializing/non-resuming version of gatherMany: -- -- Does serialize the actual Autos themselves; the -- Autos are all serialized and re-loaded/resumed when -- 'gatherMany_ f' is resumed. -- -- Does not serialize the "last outputs", so resumed Autos -- that have not yet been re-run/accessed to get a fresh output are not -- represented in the output map at first. gatherMany_ :: (Ord k, Monad m, Serialize k) => (k -> Interval m a b) -> Auto m (Map k a) (Map k b) -- | The non-serializing/non-resuming vervsion of gatherMany: -- -- Serializes neither the Autos themselves nor the "last outputs" -- --- essentially, serializes/resumes nothing. gatherMany__ :: (Ord k, Monad m) => (k -> Interval m a b) -> Auto m (Map k a) (Map k b) -- | This module provides tools for generating and manipulating "blip -- streams". The blip stream abstraction is not fundamental to -- Auto, but rather, like interval, is a very useful -- semantic tool for the denotation of many programs, games, simulations, -- and computations in general that you are likely to write with this -- library. module Control.Auto.Blip -- | When used in the context of an input or output of an Auto, a -- Blip a represents a stream that occasionally, at -- "independent" or "discrete" points, emits a value of type a. -- -- Contrast this to Interval, where things are meant to be "on" -- or "off" for contiguous chunks at a time; blip streams are "blippy", -- and Intervals are "chunky". -- -- It's here mainly because it's a pretty useful abstraction in the -- context of the many combinators found in various modules of this -- library. If you think of an Auto m a (Blip b) -- as producing a "blip stream", then there are various combinators and -- functions that are specifically designed to manipulate blip streams. -- -- For the purposes of the semantics of what Blip is supposed to -- represent, its constructors are hidden. (Almost) all of the various -- Blip combinators (and its very useful Functor instance) -- "preserve Blipness" --- one-at-a-time occurrences remain -- one-at-a-time under all of these combinators, and you should have -- enough so that direct access to the constructor is not needed. -- -- If you are creating a framework, library, or backend, you might want -- to manually create blip stream-producing Autos for your users -- to access. In this case, you can import the constructors and useful -- internal (and, of course, semantically unsafe) functions from -- Control.Auto.Blip.Internal. data Blip a -- | Takes an Auto m a b (an Auto that turns -- incoming as into outputting bs) into an -- Auto m (Blip a) (Blip b); the original -- Auto is lifted to only be applied to emitted contents of a blip -- stream. -- -- When the stream emits, the original Auto is "stepped" with the -- emitted value; when it does not, it is paused and frozen until the -- next emission. -- --
--   >>> let sums = perBlip (sumFrom 0)
--   
--   >>> let blps = eachAt 2 [1,5,2]
--   
--   >>> take 8 . streamAuto' blps $ repeat ()
--   [NoBlip, Blip 1, NoBlip, Blip 5, NoBlip, Blip 2, NoBlip, NoBlip]
--   
--   >>> take 8 . streamAuto' (sums . blps) $ repeat ()
--   [NoBlip, Blip 1, NoBlip, Blip 6, NoBlip, Blip 8, NoBlip, NoBlip]
--   
perBlip :: Monad m => Auto m a b -> Auto m (Blip a) (Blip b) -- | Merge two blip streams together; the result emits with either -- of the two merged streams emit. When both emit at the same time, emit -- the result of applying the given function on the two emitted values. -- -- Note that this might be too strict for some purposes; see -- mergeL and mergeR for lazier alternatives. merge :: (a -> a -> a) -> Blip a -> Blip a -> Blip a -- | Merges two blip streams together into one, which emits either -- of the original blip streams emit. If both emit at the same time, the -- left (first) one is favored. -- -- Lazy on the second stream if the first stream is emitting. -- -- If we discount laziness, this is merge const. mergeL :: Blip a -> Blip a -> Blip a -- | Merges two blip streams together into one, which emits either -- of the original blip streams emit. If both emit at the same time, the -- right (second) one is favored. -- -- Lazy on the first stream if the second stream is emitting. -- -- If we discount laziness, this is merge (flip -- const). mergeR :: Blip a -> Blip a -> Blip a -- | Merge all the blip streams together into one, favoring the first -- emitted value. mergeLs :: [Blip a] -> Blip a -- | Merge all the blip streams together into one, favoring the last -- emitted value. mergeRs :: [Blip a] -> Blip a -- | Merge all of the blip streams together, using the given merging -- function associating from the right. -- -- DEPRECATED: In its current form, foldrB will disappear -- in 0.5. The new version will be: -- --
--   foldrB :: (a -> a -> a) -> [Blip a] -> Blip b
--   
-- -- Which will not emit if nothing emits. This really was supposed to be -- the intended behavior originally. -- -- For this reason, please do not use this anymore. As it is currently -- implemented, it doesn't really make any sense, either. -- -- To begin using the new behavior, you can use: -- --
--   foldr (merge f) mempty
--   
-- | Deprecated: Starting in v0.5, will have new functionality. foldrB :: (a -> a -> a) -> a -> [Blip a] -> Blip a -- | Merge all of the blip streams together, using the given merging -- function associating from the left. -- -- DEPRECATED: In its current form, foldlB' will disappear -- in 0.5. The new version will be: -- --
--   foldlB' :: (a -> a -> a) -> [Blip a] -> Blip b
--   
-- -- Which will not emit if nothing emits. This really was supposed to be -- the intended behavior originally. -- -- For this reason, please do not use this anymore. As it is currently -- implemented, it doesn't really make any sense, either. -- -- To begin using the new behavior, you can use: -- --
--   foldl' (merge f) mempty
--   
-- | Deprecated: Starting in v0.5, will have new functionality. foldlB' :: (a -> a -> a) -> a -> [Blip a] -> Blip a -- | An Auto that runs every input through a a -> -- Maybe b test and produces a blip stream that emits the -- value inside every Just result. -- -- Particularly useful with prisms from the lens package, where -- things like emitJusts (preview _Right) will emit the -- b whenever the input Either a b stream is a -- Right. -- -- Warning! Carries all of the same dangers of emitOn. You can -- easily break blip semantics with this if you aren't sure what you are -- doing. Remember to only emit at discrete, separate occurences, and not -- for interval-like (on and off for chunks at a time) things. For -- interval semantics, we have Control.Auto.Interval. -- -- See the examples of emitOn for more concrete good/bad use -- cases. emitJusts :: (a -> Maybe b) -> Auto m a (Blip b) -- | 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) -- | An Auto that emits whenever it receives a Just input, -- with the value inside the Just. -- -- Warning! Carries all of the same dangers of emitOn. You can -- easily break blip semantics with this if you aren't sure what you are -- doing. Remember to only emit at discrete, separate occurences, and not -- for interval-like (on and off for chunks at a time) things. For -- interval semantics, we have Control.Auto.Interval. -- -- See the examples of emitOn for more concrete good/bad use -- cases. -- --
--   onJusts == emitJusts id
--   
onJusts :: Auto m (Maybe a) (Blip a) -- | 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. -- --
--   onEithers == emitEithers id
--   
onEithers :: Auto m (Either a b) (Blip a, Blip b) -- | Produces a blip stream that emits the input value whenever the input -- satisfies a given predicate. -- -- Warning! This Auto has the capability of "breaking" blip -- semantics. Be sure you know what you are doing when using this. Blip -- streams are semantically supposed to only emit at discrete, separate -- occurrences. Do not use this for interval-like (on and off for chunks -- at a time) things; each input should be dealt with as a separate -- thing. -- -- For interval semantics, we have Interval from -- Control.Auto.Interval. -- -- Good example: -- --
--   -- is only emitting at discrete blips
--   emitOn even . iterator (+ 1) 0
--   
-- -- Bad examples: -- --
--   -- is emitting for "durations" or "intervals" of time.
--   emitOn (< 10) . iterator (+ 1) 0
--   
--   emitOn (const True) . foo
--   
-- -- These bad examples would be good use cases of Interval. -- -- Can be particularly useful with prisms from the lens package, -- where things like emitOn (has _Right) and emitOn (hasn't -- _Right) will emit the input Either a b whenever it is or -- isn't a Right. See emitJusts for more common uses with -- lens. emitOn :: (a -> Bool) -> Auto m a (Blip a) -- | 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 -> Auto m (Blip a) a -- | fromBlipsWith d f is an Auto that decomposes -- the incoming blip stream by constantly outputting d except -- when the stream emits, and outputs the result of applying f -- to the emitted value when it does. fromBlipsWith :: b -> (a -> b) -> Auto m (Blip a) b -- | Collapse a blip stream of as into a stream of `Maybe a`'s asMaybes :: Auto m (Blip a) (Maybe a) -- | holdWith y0 is an Auto whose output is always -- the /most recently emitted/ value from the input blip stream. Before -- anything is emitted, y0 is outputted as a placeholder. -- -- Contrast with hold from Control.Auto.Interval. holdWith :: Serialize a => a -> Auto m (Blip a) a -- | A non-serializing/non-resumable version of holdWith. holdWith_ :: a -> Auto m (Blip a) a -- | 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 -- | An Auto that ignores its input and produces a blip stream never -- emits. never :: Auto m a (Blip b) -- | Produces a blip stream that emits with the first received input value, -- and never again after that. -- -- Often used with pure: -- --
--   immediately . pure "Emit me!"
--   
-- -- Or, in proc notation: -- --
--   blp <- immediately -< "Emit me!"
--   
-- -- to get a blip stream that emits a given value (eg., "Emit me!") once -- and stops emitting ever again. -- --
--   >>> streamAuto' (immediately . pure "Emit me!") [1..5]
--   [Blip "Emit Me!", NoBlip, NoBlip, NoBlip, NoBlip]
--   
immediately :: Auto m a (Blip a) -- | Produces a blip stream that only emits once, with the input value on -- the given step number. It emits the input on that many steps. -- --
--   immediately == inB 1
--   
inB :: Int -> Auto m a (Blip a) -- | every n is an Auto that emits with the incoming -- inputs on every nth input value. First emitted value is on -- the nth step. -- -- Will obviously break blip semantics when you pass in 1. every :: Int -> Auto m a (Blip a) -- | eachAt n xs is an Auto that ignores its input -- and creates a blip stream that emits each element of xs one -- at a time, evey n steps. First emitted value is at step -- n. -- -- Once the list is exhausted, never emits again. -- -- Obviously breaks blip semantics when you pass in 1. -- -- The process of serializing and resuming this Auto is O(n) space -- and time with the length of xs. So don't serialize this if -- you plan on passing an infinite list :) See -- Control.Auto.Generate for more options. -- --
--   eachAt n xs == perBlip (fromList xs) . every n
--   
eachAt :: Serialize b => Int -> [b] -> Auto m a (Blip b) -- | The non-serializing/non-resumable version of eachAt. eachAt_ :: Int -> [b] -> Auto m a (Blip b) -- | 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]) -- | The non-serializing/non-resuming version of collectN collectN_ :: Int -> Auto m a (Blip [a]) -- | Re-emits every emission from the input blip stream, but replaces its -- value with the given value. -- --
--   tagBlips x == modifyBlips (const x)
--   
tagBlips :: b -> Auto m (Blip a) (Blip b) -- | Re-emits every emission from the input blip stream, but applies the -- given function to the emitted value. modifyBlips :: (a -> b) -> Auto m (Blip a) (Blip b) -- | Takes two Autos producing blip streams and returns a "merged" -- Auto that emits when either of the original Autos emit. -- When both emit at the same time, the left (first) one is favored. -- --
--   a1 <& a2 == mergeL <$> a1 <*> a2
--   
(<&) :: Monad m => Auto m a (Blip b) -> Auto m a (Blip b) -> Auto m a (Blip b) -- | Takes two Autos producing blip streams and returns a "merged" -- Auto that emits when either of the original Autos emit. -- When both emit at the same time, the right (second) one is favored. -- --
--   a1 &> a2 == mergeR <$> a1 <*> a2
--   
(&>) :: Monad m => Auto m a (Blip b) -> Auto m a (Blip b) -> Auto m a (Blip b) -- | Supress all upstream emitted values except for the very first. once :: Auto m (Blip a) (Blip a) -- | Suppress only the first emission coming from upstream, and let all the -- others pass uninhibited. notYet :: Auto m (Blip a) (Blip a) -- | Takes in a blip stream and outputs a blip stream where each emission -- is delayed/lagged by one step. -- --
--   >>> streamAuto' (emitOn (\x -> x `mod` 3 == 0)) [1..9]
--   
--   >>> [NoBlip, NoBlip, Blip 3, NoBlip, NoBlip, Blip 6, NoBlip, NoBlip, Blip 9]
--   
--   >>> streamAuto' (lagBlips . emitOn (\x -> x `mod` 3 == 0)) [1..9]
--   
--   >>> [NoBlip, NoBlip, NoBlip, Blip 3, NoBlip, NoBlip, Blip 6, NoBlip, NoBlip]
--   
lagBlips :: Serialize a => Auto m (Blip a) (Blip a) -- | The non-serializing/non-resuming version of lagBlips. lagBlips_ :: Auto m (Blip a) (Blip a) -- | Suppress all upstream emissions when the predicate (on the emitted -- value) fails. filterB :: (a -> Bool) -> Auto m (Blip a) (Blip a) -- | Splits a blip stream based on a predicate. Takes in one blip -- stream and produces two: the first emits whenever the input emits with -- a value that passes the predicate, and the second emits whenever the -- input emits with a value that doesn't. splitB :: (a -> Bool) -> Auto m (Blip a) (Blip a, Blip a) -- | 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. mapMaybeB :: (a -> Maybe b) -> Auto m (Blip a) (Blip b) -- | Splits a blip stream based on a predicate returning an -- Either. All Left results go to the first output stream, -- and all Right results go to the second. -- -- On an 'a -> Either () b', is roughly analogous to mapMaybeB. -- On an 'a -> Either () ()', is roughly analogous to filterB -- or splitB. splitEitherB :: (a -> Either b c) -> Auto m (Blip a) (Blip b, Blip c) -- | 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)) -- | The non-serializing/non-resuming version of collectB. collectB_ :: Auto m (Blip a, Blip b) (Blip (a, b)) -- | 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]) -- | The non-serializing/non-resuming version of collectBs. collectBs_ :: Int -> Auto m (Blip a) (Blip [a]) -- | Collapses a blip stream of blip streams into single blip -- stream. that emits whenever the inner-nested stream emits. joinB :: Auto m (Blip (Blip a)) (Blip a) -- | takeB n allows only the first n emissions to -- pass; it suppresses all of the rest. takeB :: Int -> Auto m (Blip a) (Blip a) -- | Allow all emitted valuesto pass until the first that fails the -- predicate. takeWhileB :: (a -> Bool) -> Auto m (Blip a) (Blip a) -- | dropB n suppresses the first n emissions from -- upstream and passes through the rest uninhibited. dropB :: Int -> Auto m (Blip a) (Blip a) -- | Suppress all emited values until the first one satisfying the -- predicate, then allow the rest to pass through. dropWhileB :: (a -> Bool) -> Auto m (Blip a) (Blip a) -- | Accumulates all emissions in the incoming blip stream with a "folding -- function", with a given starting value. b -> a -> b, -- with a starting b, gives Auto m (Blip a) -- (Blip b). -- -- The resulting blip stream will emit every time the input stream emits, -- but with the "accumulated value". -- -- Basically accum, but on blip stream emissions. -- --
--   accumB f x0 == perBlip (accum f x0)
--   
accumB :: Serialize b => (b -> a -> b) -> b -> Auto m (Blip a) (Blip b) -- | The non-serializing/non-resuming version of accumB. accumB_ :: (b -> a -> b) -> b -> Auto m (Blip a) (Blip b) -- | The output is the result of folding up every emitted value seen thus -- far, with the given folding function and initial value. -- --
--   scanB f x0 == holdWith x0 . accumB f x0
--   
-- --
--   >>> let a = scanB (+) 0 . eachAt 2 [1,2,3]
--   
--   >>> take 8 . streamAuto' a $ repeat ()
--   [0, 1, 1, 3, 3, 6, 6, 6, 6]
--   
scanB :: Serialize b => (b -> a -> b) -> b -> Auto m (Blip a) b -- | The non-serializing/non-resuming version of scanB. scanB_ :: (b -> a -> b) -> b -> Auto m (Blip a) b -- | The output is the mconcat (monoid sum) of all emitted values -- seen this far. mscanB :: (Monoid a, Serialize a) => Auto m (Blip a) a -- | The non-serializing/non-resuming version of mscanB. mscanB_ :: Monoid a => Auto m (Blip a) a -- | The output is the number of emitted values received from the upstream -- blip stream so far. countB :: Auto m (Blip a) Int -- | Blip stream that emits whenever the input value changes. Emits with -- the new value. -- -- Warning: Note that, when composed on a value that is never expected to -- keep the same value twice, this technically breaks blip semantics. onChange :: (Serialize a, Eq a) => Auto m a (Blip a) -- | The non-serializing/non-resumable version of onChange. onChange_ :: Eq a => Auto m a (Blip a) -- | Blip stream that emits whenever the predicate applied to the input -- switches from false to true. Emits with the triggering input value. became :: Serialize a => (a -> Bool) -> Auto m a (Blip a) -- | The non-serializing/non-resumable version of became. became_ :: (a -> Bool) -> Auto m a (Blip a) -- | Like became, but emits a '()' instead of the triggering input -- value. -- -- Useful because it can be serialized without the output needing a -- Serialize instance. became' :: (a -> Bool) -> Auto m a (Blip ()) -- | Blip stream that emits whenever the predicate applied to the input -- switches from true to false. Emits with the triggering input value. noLonger :: Serialize a => (a -> Bool) -> Auto m a (Blip a) -- | The non-serializing/non-resumable version of noLonger. noLonger_ :: (a -> Bool) -> Auto m a (Blip a) -- | Like noLonger, but emits a '()' instead of the triggering input -- value. -- -- Useful because it can be serialized without the output needing a -- Serialize instance. noLonger' :: (a -> Bool) -> Auto m a (Blip ()) -- | Blip stream that emits whenever the predicate applied to the input -- switches from true to false or false to true. Emits with the -- triggering input value. onFlip :: (Serialize a, Monad m) => (a -> Bool) -> Auto m a (Blip a) -- | The non-serializing/non-resumable version of onFlip. onFlip_ :: Monad m => (a -> Bool) -> Auto m a (Blip a) -- | Like onFlip, but emits a Bool instead of the triggering -- input value. An emitted True indicates that the predicate just -- became true; an emitted False indicates that the predicate just -- became false. -- -- Useful because it can be serialized without the output needing a -- Serialize instance. onFlip' :: Monad m => (a -> Bool) -> Auto m a (Blip Bool) -- | This module exports the preferred ways of interacting with the -- underlying Monad of the Auto type, including accessing, -- executing, and manipulating such effects. module Control.Auto.Effects -- | Applies the given "monadic function" (function returning a monadic -- action) to every incoming item; the result is the result of executing -- the action returned. -- -- Note that this essentially lifts a "Kleisli arrow"; it's like -- arr, but for "monadic functions" instead of normal functions: -- --
--   arr  :: (a -> b)   -> Auto m a b
--   arrM :: (a -> m b) -> Auto m a b
--   
-- --
--   arrM f . arrM g == arrM (f <=< g)
--   
-- -- One neat trick you can do is that you can "tag on effects" to a normal -- Auto by using *> from Control.Applicative. For -- example: -- --
--   >>> let a = arrM print *> sumFrom 0
--   
--   >>> ys <- streamAuto a [1..5]
--   1                -- IO output
--   2
--   3
--   4
--   5
--   
--   >>> ys
--   [1,3,6,10,15]    -- the result
--   
-- -- Here, a behaves "just like" sumFrom -- 0...except, when you step it, it prints out to stdout as a -- side-effect. We just gave automatic stdout logging behavior! arrM :: (a -> m b) -> Auto m a b -- | To get every output, executes the monadic action and returns the -- result as the output. Always ignores input. -- -- This is basically like an "effectful" pure: -- --
--   pure   :: b   -> Auto m a b
--   effect :: m b -> Auto m a b
--   
-- -- The output of pure is always the same, and the output of -- effect is always the result of the same monadic action. Both -- ignore their inputs. -- -- Fun times when the underling Monad is, for instance, -- Reader. -- --
--   >>> let a = effect ask    :: Auto (Reader b) a b
--   
--   >>> let r = evalAuto a () :: Reader b b
--   
--   >>> runReader r "hello"
--   "hello"
--   
--   >>> runReader r 100
--   100
--   
-- -- If your underling monad has effects (IO, State, -- Maybe, Writer, etc.), then it might be fun to take -- advantage of *> from Control.Applicative to "tack on" -- an effect to a normal Auto: -- --
--   >>> let a = effect (modify (+1)) *> sumFrom 0 :: Auto (State Int) Int Int
--   
--   >>> let st = streamAuto a [1..10]
--   
--   >>> let (ys, s') = runState st 0
--   
--   >>> ys
--   [1,3,6,10,15,21,28,36,45,55]
--   
--   >>> s'
--   10
--   
-- -- Our Auto a behaves exactly like sumFrom -- 0, except at each step, it also increments the underlying/global -- state by one. It is sumFrom 0 with an "attached -- effect". effect :: m b -> Auto m a b -- | The input stream is a stream of monadic actions, and the output stream -- is the result of their executions, through executing them. effects :: Monad m => Auto m (m a) a -- | Maps one blip stream to another; replaces every emitted value with the -- result of the monadic function, executing it to get the result. arrMB :: Monad m => (a -> m b) -> Auto m (Blip a) (Blip b) -- | Maps one blip stream to another; replaces every emitted value with the -- result of a fixed monadic action, run every time an emitted value is -- received. effectB :: Monad m => m b -> Auto m (Blip a) (Blip b) -- | Outputs the identical blip stream that is received; however, every -- time it sees an emitted value, executes the given monadic action on -- the side. execB :: Monad m => m b -> Auto m (Blip a) (Blip a) -- | The very first output executes a monadic action and uses the result as -- the output, ignoring all input. From then on, it persistently outputs -- that first result. -- -- Like execOnce, except outputs the result of the action instead -- of ignoring it. -- -- Useful for loading resources in IO on the "first step", like a word -- list: -- --
--   dictionary :: Auto IO a [String]
--   dictionary = cache (lines $ readFile "wordlist.txt")
--   
cache :: (Serialize b, Monad m) => m b -> Auto m a b -- | Always outputs '()', but when asked for the first output, executes the -- given monadic action. -- -- Pretty much like cache, but always outputs '()'. execOnce :: Monad m => m b -> Auto m a () -- | The non-resumable/non-serializable version of cache. Every time -- the Auto is deserialized/reloaded, it re-executes the action to -- retrieve the result again. -- -- Useful in cases where you want to "re-load" an expensive resource on -- every startup, instead of saving it to in the save states. -- --
--   dictionary :: Auto IO a [String]
--   dictionary = cache_ (lines $ readFile "dictionary.txt")
--   
cache_ :: Monad m => m b -> Auto m a b -- | The non-resumable/non-serializable version of execOnce. Every -- time the Auto is deserialized/reloaded, the action is -- re-executed again. execOnce_ :: Monad m => m b -> Auto m a () -- | Swaps out the underlying Monad of an Auto using the -- given monad morphism "transforming function", a natural -- transformation. -- -- Basically, given a function to "swap out" any m a with an -- m' a, it swaps out the underlying monad of the Auto. -- -- This forms a functor, so you rest assured in things like this: -- --
--   hoistA id == id
--   hoistA f a1 . hoistA f a2 == hoistA f (a1 . a2)
--   
hoistA :: (Monad m, Monad m') => (forall c. m c -> m' c) -> Auto m a b -> Auto m' a b -- | Generalizes an Auto' a b to an Auto m a -- b' for any Monad m, using hoist. -- -- You generally should be able to avoid using this if you never directly -- write any Auto's and always write 'Auto m' parameterized over -- all Monads, but...in case you import one from a library or -- something, you can use this. generalizeA :: Monad m => Auto' a b -> Auto m a b -- | Unrolls the underlying ReaderT of an Auto into an -- Auto that takes in the input "environment" every turn in -- addition to the normal input. -- -- So you can use any ReaderT r m as if it were an -- m. Useful if you want to compose and create some isolated -- Autos with access to an underlying environment, but not your -- entire program. -- -- Also just simply useful as a convenient way to use an Auto over -- Reader with stepAuto and friends. -- -- When used with Reader r, it turns an Auto -- (Reader r) a b into an Auto' (a, r) b. runReaderA :: Monad m => Auto (ReaderT r m) a b -> Auto m (a, r) b -- | Takes an Auto that operates under the context of a read-only -- environment, an environment value, and turns it into a normal -- Auto that always "sees" that value when it asks for one. -- --
--   >>> let a   = effect ask :: Auto (Reader b) a b
--   
--   >>> let rdr = streamAuto' a [1..5] :: Reader b [b]
--   
--   >>> runReader rdr "hey"
--   ["hey", "hey", "hey", "hey", "hey"]
--   
-- -- Useful if you wanted to use it inside/composed with an Auto -- that does not have a global environment: -- --
--   bar :: Auto' Int String
--   bar = proc x -> do
--       hey <- sealReader (effect ask) "hey" -< ()
--       id -< hey ++ show x
--   
-- --
--   >>> streamAuto' bar [1..5]
--   ["hey1", "hey2", "hey3", "hey4", "hey5"]
--   
-- -- Note that this version serializes the given r environment, so -- that every time the Auto is reloaded/resumed, it resumes with -- the originally given r environment, ignoring whatever -- r is given to it when trying to resume it. If this is not the -- behavior you want, use sealReader_. -- -- Reader is convenient because it allows you to "chain" and -- "compose" Autos with a common environment, instead of -- explicitly passing in values every time. For a convenient way of -- generating Autos under ReaderT, and also for some -- motivating examples, see readerA and runReaderA. sealReader :: (Monad m, Serialize r) => Auto (ReaderT r m) a b -> r -> Auto m a b -- | The non-resuming/non-serializing version of sealReader. Does -- not serialize/reload the r environment, so that whenever you -- "resume" the Auto, it uses the new r given when you -- are trying to resume, instead of loading the originally given one. -- -- DOES serialize the actual Auto! sealReader_ :: Monad m => Auto (ReaderT r m) a b -> r -> Auto m a b -- | Transforms an Auto on two input streams ( a "normal input" -- stream a and an "environment input stream" r) into -- an Auto on one input stream a with an underlying -- environment r through a Reader monad. -- -- Why is this useful? Well, if you have several Autos that all -- take in a side r stream, and you want to convey that every -- single one should get the same r at every step, you -- can instead have all of them pull from a common underlying global -- environment. -- -- Note: Function is the inverse of runReaderA: -- --
--   readerA . runReaderA == id
--   runReaderA . readerA == id
--   
readerA :: Monad m => Auto m (a, r) b -> Auto (ReaderT r m) a b -- | Takes an Auto that operates under the context of a read-only -- environment, an environment value, and turns it into a normal -- Auto that always gets its environment value from an -- MVar. -- -- This allows for "hot swapping" configurations. If your whole program -- runs under a configuration data structure as the environment, you can -- load the configuration data to the MVar and then "hot swap" it -- out by just changing the value in the MVar from a different -- thread. -- -- Note that this will block on every "step" until the MVar is -- readablefullhas a value, if it does not. -- -- Basically a disciplined wrapper/usage over sealReaderM. sealReaderMVar :: MonadIO m => Auto (ReaderT r m) a b -> MVar r -> Auto m a b -- | Takes an Auto that operates under the context of a read-only -- environment, an environment value, and turns it into a normal -- Auto that always gets its environment value by executing an -- action every step in the underlying monad. -- -- This can be abused to write unmaintainble code really fast if you -- don't use it in a disciplined way. One possible usage is to query a -- database in IO (or MonadIO) for a value at every step. -- If you're using underlying global state, you can use it to query that -- too, with get or gets. You could even use -- getLine, maybe, to get the result from standard input at every -- step. -- -- One disciplined wrapper around this is sealReaderMVar, where -- the environment at every step comes from reading an MVar. This -- can be used to "hot swap" configuration files. sealReaderM :: Monad m => Auto (ReaderT r m) a b -> m r -> Auto m a b -- | Transforms an Auto on with two output streams (a "normal output -- stream" b, and a "logging output stream" w) into an -- Auto with just one output stream a, funneling the -- logging stream w into an underlying WriterT monad. -- -- Note: Function is the inverse of runWriterA: -- --
--   writerA . runWriterA == id
--   runWriterA . writerA == id
--   
writerA :: (Monad m, Monoid w) => Auto m a (b, w) -> Auto (WriterT w m) a b -- | Unrolls the underlying WriterT w m -- Monad, so that an Auto that takes in a stream of -- a and outputs a stream of b will now output a stream -- (b, w), where w is the "new log" of the underlying -- Writer at every step. -- -- Examples: -- --
--   foo :: Auto (Writer (Sum Int)) Int Int
--   foo = effect (tell 1) *> effect (tell 1) *> sumFrom 0
--   
-- --
--   >>> let fooWriter = streamAuto foo
--   
--   >>> runWriter $ fooWriter [1..10]
--   ([1,3,6,10,15,21,28,36,45,55], Sum 20)
--   
-- -- foo increments an underlying counter twice every time it is -- stepped; its "result" is just the cumulative sum of the inputs. -- -- When we "stream" it, we get a [Int] -> Writer (Sum -- Int) [Int]...which we can give an input list and -- runWriter it, getting a list of outputs and a "final -- accumulator state" of 10, for stepping it ten times. -- -- However, if we use runWriterA before streaming it, we get: -- --
--   >>> let fooW = runWriterA foo
--   
--   >>> streamAuto' fooW [1..10]
--   [ (1 , Sum 2), (3 , Sum 2), (6 , Sum 2)
--   , (10, Sum 2), (15, Sum 2), (21, Sum 2), -- ...
--   
-- -- Instead of accumulating it between steps, we get to "catch" the -- Writer output at every individual step. -- -- We can write and compose our own Autos under Writer, -- using the convenience of a shared accumulator, and then "use them" -- with other Autos: -- --
--   bar :: Auto' Int Int
--   bar = proc x -> do
--     (y, w) <- runWriterA foo -< x
--     blah <- blah -< w
--   
-- -- And now you have access to the underlying accumulator of foo -- to access. There, w represents the continually updating -- accumulator under foo, and will be different/growing at every -- "step". -- -- For a convenient way to create an Auto under -- WriterT, see writerA. runWriterA :: (Monad m, Monoid w) => Auto (WriterT w m) a b -> Auto m a (b, w) -- | Takes an Auto that works with underlying global, mutable state, -- and "seals off the state" from the outside world. -- -- An 'Auto (StateT s m) a b' maps a stream of a to a stream of -- b, but does so in the context of requiring an initial -- s to start, and outputting a modified s. -- -- Consider this example State Auto: -- --
--   foo :: Auto (State Int) Int Int
--   foo = proc x -> do
--       execB (modify (+1)) . emitOn odd  -< x
--       execB (modify (*2)) . emitOn even -< x
--       st   <- effect get -< ()
--       sumX <- sumFrom 0  -< x
--       id    -< sumX + st
--   
-- -- On every output, the "global" state is incremented if the input is odd -- and doubled if the input is even. The stream st is always the -- value of the global state at that point. sumX is the -- cumulative sum of the inputs. The final result is the sum of the value -- of the global state and the cumulative sum. -- -- In writing like this, you lose some of the denotative properties -- because you are working with a global state that updates at every -- output. You have some benefit of now being able to work with global -- state, if that's what you wanted I guess. -- -- To "run" it, you could use streamAuto to get a -- State Int Int: -- --
--   >>> let st = streamAuto foo [1..10] :: State Int Int
--   
--   >>> runState st 5
--   ([  7, 15, 19, 36, 42, 75, 83,136,156,277], 222)
--   
-- -- (The starting state is 5 and the ending state after all of that is -- 222) -- -- However, writing your entire program with global state is a bad bad -- idea! So, how can you get the "benefits" of having small parts like -- foo be written using State, and being able to use it -- in a program with no global state? -- -- Using sealState! Write the part of your program that would like -- shared global state with State...and compose it with the rest -- as if it doesn't, locking it away! -- --
--   sealState       :: Auto (State s) a b -> s -> Auto' a b
--   sealState foo 5 :: Auto' Int Int
--   
-- --
--   bar :: Auto' Int (Int, String)
--   bar = proc x -> do
--       food <- sealState foo 5 -< x
--       id -< (food, show x)
--   
-- --
--   >>> streamAuto' bar [1..10]
--   [ (7, "1"), (15, "2"), (19, "3"), (36, "4"), (42, "5"), (75, "6") ...
--   
-- -- We say that sealState f s0 takes an input stream, and -- the output stream is the result of running the stream through -- f, first with an initial state of s0, and afterwards -- with each next updated state. -- -- If you wanted to "seal" the state and have it be untouchable to the -- outside world, yet still have a way to "monitor"/"view" it, you can -- modify the original Auto using &&&, -- effect, and 'get to get a "view" of the state: -- --
--   >>> streamAuto' (sealState (foo &&& effect get) 5) [1..10]
--   [(7,6),(15,12),(19,13),(36,26),(42,27),(75,54),(83,55),(146,110),(156,111),(277,222)]
--   
-- -- Now, every output of sealState foo 5 is tuplied up -- with a peek of its state at that point. -- -- For a convenient way of "creating" an Auto under StateT -- in the first place, see stateA. sealState :: (Monad m, Serialize s) => Auto (StateT s m) a b -> s -> Auto m a b -- | The non-resuming/non-serializing version of sealState. sealState_ :: Monad m => Auto (StateT s m) a b -> s -> Auto m a b -- | Unrolls the underlying StateT of an Auto into an -- Auto that takes in an input state every turn (in addition to -- the normal input) and outputs, along with the original result, the -- modified state. -- -- So now you can use any StateT s m as if it were an -- m. Useful if you want to compose and create some isolated -- Autos with access to an underlying state, but not your entire -- program. -- -- Also just simply useful as a convenient way to use an Auto over -- State with stepAuto and friends. -- -- When used with State s, it turns an Auto -- (State s) a b into an Auto' (a, s) (b, -- s). -- -- For a convenient way to "generate" an Auto StateT, see -- stateA runStateA :: Monad m => Auto (StateT s m) a b -> Auto m (a, s) (b, s) -- | Transforms an Auto with two input streams and two output -- streams (a "normal" input a output b stream, and a -- "state transforming" side-stream taking in s and outputting -- s), abstracts away the s stream as a modifcation to -- an underyling StateT monad. That is, your normal inputs and -- outputs are now your only inputs and outputs, and your input -- s comes from the underlying global mutable state, and the -- output s goes to update the underlying global mutable state. -- -- For example, you might have a bunch of Autos that interact with -- a global mutable state: -- --
--   foo :: Auto (StateT Double m) Int Bool
--   bar :: Auto (StateT Double m) Bool Int
--   baz :: Auto (StateT Double m) Bool String
--   
-- -- Where foo, bar, and baz all interact with -- global mutable state. You'd use them like this: -- --
--   full :: Auto (StateT Double m) Int String
--   full = proc inp -> do
--       fo <- foo -< inp
--       br <- bar -< fo
--       bz <- baz -< fo
--       id -< replicae br bz
--   
-- -- stateA allows you generate a new Auto under -- StateT: -- --
--   thing :: Auto m (Int, Double) (Bool, Double)
--   stateA thing :: Auto (StateT Double m) Int Bool
--   
-- -- So now the two side-channels are interpreted as working with the -- global state: -- --
--   full :: Auto (StateT Double m) Int String
--   full = proc inp -> do
--       fo <- foo          -< inp
--       tg <- stateA thing -< inp
--       br <- bar          -< fo || tg
--       bz <- baz          -< fo && tg
--       id -< replicae br bz
--   
-- -- You can then "seal it all up" in the end with an initial state, that -- keeps on re-running itself with the resulting state every time: -- --
--   full' :: Double -> Auto m Int String
--   full' = sealState full
--   
-- -- Admittedly, this is a bit more esoteric and dangerous (programming -- with global state? what?) than its components readerA and -- writerA; I don't actually recommend you programming with global -- state unless it really is the best solution to your problem...it tends -- to encourage imperative code/loops, and "unreasonable" and manageable -- code. See documentation for sealStateA for best practices. -- Basically every bad thing that comes with global mutable state. But, -- this is provided here for sake of completeness with readerA and -- writerA. -- -- Note: function is the inverse of runstateA. -- --
--   stateA . runStateA == id
--   runStateA . stateA == id
--   
stateA :: Monad m => Auto m (a, s) (b, s) -> Auto (StateT s m) a b -- | Like stateA, but assumes that the output is the modified state. accumA :: Monad m => Auto m (a, s) s -> Auto (StateT s m) a s -- | Unrolls the underlying Monad of an Auto if it -- happens to be Traversable ('[]', Maybe, etc.). -- -- It can turn, for example, an Auto [] a b into an -- Auto' a [b]; it collects all of the results together. -- Or an Auto Maybe a b into an Auto' a -- (Maybe b). -- -- This might be useful if you want to make some sort of "underlying -- inhibiting" Auto where the entire computation might just end up -- being Nothing in the end. With this, you can turn that -- possibly-catastrophically-failing Auto (with an underlying -- Monad of Maybe) into a normal Auto, and use it as -- a normal Auto in composition with other -- Autos...returning Just if your computation succeeded. -- --
--   runTraversableA :: Auto Maybe a b -> Interval' a b
--   
-- --
--   foo :: Auto Maybe Int Int
--   foo = arrM $ x -> if even x then Just (x div 2) else Nothing
--   
--   bar :: Auto Maybe Int Int
--   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]
--   [Just 1, Just 2, Just 3, Just 7]
--   
runTraversableA :: (Monad f, Traversable f) => Auto f a b -> Auto m a (f b) -- | 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 with the Exception. Otherwise, will output -- left. -- -- Note that you have to explicitly specify the type of the exceptions -- you are catching; see Control.Exception documentation for more -- details. catchA :: Exception e => Auto IO a b -> Auto IO a (Either e b) -- | A collection of versatile switching mechanisms. Switching is really a -- core mechanic at the heart of how to structure a lot of program -- logics. Switching from one "mode" to another, from dead to alive, from -- room to room, menu to menu...switching between Autos is a core -- part about how many programs are built. -- -- All of the switches here take advantage of either blip semantics (from -- Control.Auto.Blip) or Interval semantics (from -- Control.Auto.Interval)...so this is where maintaining -- semantically meaningful blip streams and intervals pays off! -- -- Each switch here has various examples, and you'll find many of these -- in use in the example projects. -- -- Note the naming convention going on here (also used in -- Control.Auto.Serialize): A switch "from" a blip stream is -- triggered "internally" by the Auto being switched itself; a -- switch "on" a blip stream is triggered "externally" by an Auto -- that is not swiched. module Control.Auto.Switch -- | "This, then that". Behave like the first Interval (and run its -- effects) as long as it is "on" (outputting Just). As soon as it -- turns off (is Nothing), it'll "switch over" and begin behaving -- like the second Auto forever, running the effects of the second -- Auto, too. Works well if the Autos follow interval -- semantics from Control.Auto.Interval. -- --
--   >>> let a1 = whenI (<= 4) --> pure 0
--   
--   >>> streamAuto' a1 [1..10]
--   [1, 2, 3, 4, 0, 0, 0, 0, 0, 0]
--   
-- -- (whenI only lets items satisfying the predicate pass through as -- "on", and is "off" otherwise; pure is the Auto that -- always produces the same output) -- -- Association works in a way that you can "chain" -->s, as -- long as you have an appropriate Auto (and not Interval) -- at the end: -- --
--   >>> let a2 = onFor 3 . sumFrom 0
--            --> onFor 3 . sumFrom 100
--            --> pure 0
--   
--   >>> streamAuto' a2 [1..10]
--   [1,3,6,104,109,115,0,0,0,0]
--   
-- -- a --> b --> c associates as a --> (b --> -- c) -- -- This is pretty invaluable for having Autos "step" through a -- series of different Autos, progressing their state from one -- stage to the next. Autos can control when they want to be -- "moved on" from by turning "off" (outputting Nothing). -- -- Note that recursive bindings work just fine, so: -- --
--   >>> let a3 = onFor 2 . pure "hello"
--            --> onFor 2 . pure "world"
--            --> a3
--   
--   >>> let (res3, _) = stepAutoN' 8 a3 ()
--   
--   >>> res3
--   ["hello", "hello", "world", "world", "hello", "hello", "world", "world"]
--   
-- -- the above represents an infinite loop between outputting "hello" and -- outputting "world". -- -- For serialization, an extra byte cost is incurred per invocation of -- -->. For cyclic switches like a3, every time the -- cycle "completes", it adds another layer of --> byte costs. -- For example, initially, saving a3 incurs a cost for the two -- -->s. After a3 loops once, it incurs a cost for -- another two -->s, so it costs four -->s. After -- a3 loops another time, it is like a cost of six -- -->s. So be aware that for cyclic bindings like a3, -- space for serialization grows at O(n). -- -- By the way, it might be worth contrasting this with <|!> -- and <|?> from Control.Auto.Interval, which have -- the same type signatures. Those alternative-y operators always feed -- the input to both sides, run both sides, and output the -- first Just. With <|!>, you can "switch back and -- forth" to the first Auto as soon as the first Auto is -- "on" (Just) again. -- -- -->, in contrast, runs only the first Auto -- until it is off (Nothing)...then runs only the second -- Auto. This transition is one-way, as well. (-->) :: Monad m => Interval m a b -> Auto m a b -> Auto m a b -- | A variation of -->, where the right hand side can also be an -- Interval / Maybe. The entire result is, then, a -- Maybe. Probably less useful than --> in most -- situations. (-?>) :: Monad m => Interval m a b -> Interval m a b -> Interval m a b -- | 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 -> Auto m a b -> Auto m a b -> Auto m a b -- | Takes an Auto who has both a normal output stream and a blip -- stream output stream, where the blip stream emits new Autos. -- -- You can imagine switchFrom_ as a box containing a single -- Auto like the one just described. It feeds its input into the -- contained Auto, and its output stream is the "normal value" -- output stream of the contained Auto. -- -- However, as soon as the blip stream of the contained Auto emits -- a new Auto, it replaces the contained Auto with -- the new one (just after emitting the "normal value"), and the -- whole thing starts all over again. -- -- switchFrom_ a0 will "start" with a0 already -- in the box. -- -- This is mostly useful to allow Autos to "replace themselves" or -- control their own destiny, or the behavior of their successors. -- -- In the following example, a1 is an Auto that behaves -- like a cumulative sum but also outputs a blip stream that will emit an -- Auto containing pure 100 (the Auto that -- always emits 100) after three steps. -- --
--   a1 :: Auto' Int (Int, Blip (Auto' Int Int))
--   a1 = proc x -> do
--       sums       <- sumFrom 0 -< x
--       switchBlip <- inB 4     -< pure 100
--       id -< (sums, switchBlip)
--   
--   -- alternatively
--   a1' = sumFrom 0 &&& (tagBlips (pure 100) . inB 4)
--   
-- -- So, switchFrom_ a1 will be the output of -- count for three steps, and then switch to pure -- 100 afterwards (when the blip stream emits): -- --
--   >>> streamAuto' (switchFrom_ a1) [1..10]
--   [1,3,6,10,100,100,100,100,100,100]
--   
-- -- This is fun to use with recursion, so you can get looping switches: -- --
--   a2 :: Auto' Int (Int, Blip (Auto' Int Int))
--   a2 = proc x -> do
--       sums       <- sumFrom 0 -< x
--       switchBlip <- inB 3     -< switchFrom_ a2
--       id -< (c, switchBlip)
--   
--   -- alternatively
--   a2' = sumFrom 0 &&& (tagBlips (switchFrom_ a2') . inB 3)
--   
-- --
--   >>> streamAuto' (switchFrom_ a2) [101..112]
--   [ 101, 203, 306 -- first 'sumFrom', on first three items [101, 102, 103]
--   , 104, 209, 315 -- second 'sumFrom', on second three items [104, 105, 106]
--   , 107, 215, 324 -- third 'sumFrom', on third three items [107, 108, 109]
--   , 110, 221, 333 -- final 'sumFrom', on fourth three items [110, 111, 112]
--   ]
--   
-- -- Note that this combinator is inherently unserializable, so you are -- going to lose all serialization capabilities if you use this. So sad, -- I know! :( This fact is reflected in the underscore suffix, as per -- convention. -- -- If you want to use switching and have serialization, you can -- use the perfectly serialization-safe alternative, switchFromF, -- which slightly less powerful in ways that are unlikely to be missed in -- practical usage. That is, almost all non-contrived real life usages of -- switchFrom_ can be recovered using switchFromF. switchFrom_ :: Monad m => Auto m a (b, Blip (Auto m a b)) -> Auto m a b -- | You can think of this as a little box containing a single Auto -- inside. Takes two input streams: an input stream of normal values, and -- a blip stream containing Autos. It feeds the input stream into -- the contained Auto...but every time the input blip stream emits -- with a new Auto, replaces the contained Auto with -- the emitted one. Then starts the cycle all over, immediately giving -- the new Auto the received input. -- -- Useful for being able to externally "swap out" Autos for a -- given situation by just emitting a new Auto in the blip stream. -- -- For example, here we push several Autos one after the other -- into the box: sumFrom 0, productFrom -- 1, and count. eachAt_ 4 emits each -- Auto in the given list every four steps, starting on the -- fourth. -- --
--   newAutos :: Auto' Int (Blip (Auto' Int Int))
--   newAutos = eachAt_ 4 [sumFrom 0, productFrom 1, count]
--   
--   a :: Auto' Int Int
--   a = proc i -> do
--       blipAutos <- newAutos -< ()
--       switchOn_ (pure 0)    -< (i, blipAutos)
--   
--   -- alternatively
--   a' = switchOn_ (pure 0) . (id &&& newAutos)
--   
-- --
--   >>> streamAuto' a [1..12]
--   [ 1,  3,   6           -- output from sumFrom 0
--   , 4, 20, 120           -- output from productFrom 1
--   , 0,  1,   2, 3, 4, 5] -- output from count
--   
-- -- Like switchFrom_, this combinator is inherently unserializable. -- So if you use it, you give up serialization for your Autos. -- This is reflected in the underscore suffix. -- -- If you wish to have the same switching devices but keep serialization, -- you can use switchOnF, which is slightly less powerful, but -- should be sufficient for all practical use cases. switchOn_ :: Monad m => Auto m a b -> Auto m (a, Blip (Auto m a b)) b -- | Essentially identical to switchOn_, except instead of taking in -- a blip stream of new Autos to put into the box, takes a blip -- stream of c --- and switchOnF uses the c to -- create the new Auto to put in the box. -- -- Here is the equivalent of the two examples from switchOn_, -- implemented with switchOnF; see the documentatino for -- switchOn_ for a description of what they are to do. -- --
--   newAuto :: Int -> Auto' Int Int
--   newAuto 1 = sumFrom 0
--   newAuto 2 = productFrom 1
--   newAuto 3 = count
--   newAuto _ = error "Do you expect rigorous error handling from a toy example?"
--   
--   a :: Auto' Int Int
--   a = proc i -> do
--       blipAutos <- eachAt 4 [1,2,3] -< ()
--       switchOnF_ newAuto (pure 0) -< (i, blipAutos)
--   
-- --
--   >>> streamAuto' a [1..12]
--   [ 1,  3,   6           -- output from sumFrom 0
--   , 4, 20, 120           -- output from productFrom 1
--   , 0,  1,   2, 3, 4, 5] -- output from count
--   
-- -- Instead of sending in the "replacement Auto", sends in a -- number, which corresponds to a specific replacement Auto. -- -- As you can see, all of the simple examples from switchOn_ can -- be implemented in switchOnF...and so can most real-life -- examples. The advantage is that switchOnF is serializable, and -- switchOn_ is not. switchOnF :: (Monad m, Serialize c) => (c -> Auto m a b) -> Auto m a b -> Auto m (a, Blip c) b -- | The non-serializing/non-resuming version of switchOnF. You sort -- of might as well use switchOn_; this version might give rise to -- more "disciplined" code, however, by being more restricted in power. switchOnF_ :: Monad m => (c -> Auto m a b) -> Auto m a b -> Auto m (a, Blip c) b -- | Essentially identical to switchFrom_, except insead of the -- Auto outputting a blip stream of new Autos to replace -- itself with, it emits a blip stream of c --- and -- switchFromF uses the c to create the new Auto. -- -- Here is the equivalent of the two examples from switchFrom_, -- implemented with switchFromF; see the documentation for -- switchFrom_ for a description of what they are to do. -- --
--   a1 :: Auto' Int (Int, Blip Int)
--   a1 = proc x -> do
--       sums       <- sumFrom 0 -< x
--       switchBlip <- inB 4     -< 100
--       id -< (sums, switchBlip)
--   
--   -- alternatively
--   a1' = sumFrom 0 &&& (tagBlips 100 . inB 4)
--   
-- --
--   >>> streamAuto' (switchFromF (\x -> (x,) <$> never) a1) [1..10]
--   [1,3,6,10,100,100,100,100,100,100]
--   
-- --
--   a2 :: Auto' Int (Int, Blip ())
--   a2 = proc x -> do
--       sums       <- sumFrom 0 -< x
--       switchBlip <- inB 3     -< ()
--       id -< (sums, switchBlip)
--   
--   -- alternatively
--   a2' = sumFrom 0 &&& (tagBlips () . inB 3)
--   
-- --
--   >>> streamAuto' (switchFromF (const a2) a2) [101..112]
--   [ 101, 203, 306  -- first 'sumFrom', on first three items [101, 102, 103]
--   , 104, 209, 315  -- second 'sumFrom', on second three items [104, 105, 106]
--   , 107, 215, 324  -- third 'sumFrom', on third three items [107, 108, 109]
--   , 110, 221, 333] -- final 'sumFrom', on fourth three items [110, 111, 112]
--   
-- -- Or, if you're only ever going to use a2 in switching form: -- --
--   a2s :: Auto' Int Int
--   a2s = switchFromF (const a2s) $ proc x -> do
--             sums       <- sumFrom 0 -< x
--             switchBlip <- inB 3     -< ()
--             id -< (c, swichBlip)
--   
--   -- or
--   a2s' = switchFromF (const a2s')
--        $ sumFrom 0 &&& (tagBlips () . inB 3)
--   
-- --
--   >>> streamAuto' a2s [101..112]
--   [101, 203, 306, 104, 209, 315, 107, 215, 324, 110, 221, 333]
--   
-- -- As you can see, all of the simple examples from switchFrom_ can -- be implemented in switchFromF...and so can most real-life -- examples. The advantage is that switchFromF is serializable, -- and switchFrom_ is not. -- -- Note that for the examples above, instead of using const, we -- could have actually used the input parameter to create a new -- Auto based on what we outputted. switchFromF :: (Monad m, Serialize c) => (c -> Auto m a (b, Blip c)) -> Auto m a (b, Blip c) -> Auto m a b -- | The non-serializing/non-resuming version of switchFromF. You -- sort of might as well use switchFrom_; this version might give -- rise to more "disciplined" code, however, by being more restricted in -- power. switchFromF_ :: Monad m => (c -> Auto m a (b, Blip c)) -> Auto m a (b, Blip c) -> Auto m a b -- | Takes an innocent Auto and wraps a "reset button" around it. It -- behaves just like the original Auto at first, but when the -- input blip stream emits, the internal Auto is reset back to the -- beginning. -- -- Here we have sumFrom wrapped around a reset button, and we -- send in a blip stream that emits every 4 steps; so every 4th step, the -- whole summer resets. -- --
--   >>> let a = resetOn (sumFrom 0) . (id &&& every 4)
--   
--   >>> streamAuto' a [101..112]
--   [ 101, 203, 306
--   , 104, 209, 315  -- resetted!
--   , 107, 215, 324  -- resetted!
--   , 110, 221, 333] -- resetted!
--   
resetOn :: Monad m => Auto m a b -> Auto m (a, Blip c) b -- | Gives an Auto the ability to "reset" itself on command -- -- Basically acts like fmap fst -- --
--   fmap fst :: Monad m => Auto m a (b, Blip c) -> Auto m a b
--   
-- -- But...whenever the blip stream emits..."resets" the Auto back -- to the original state, as if nothing ever happened. -- -- Note that this resetting happens on the step after the blip -- stream emits. -- -- Here is a summer that sends out a signal to reset itself whenever the -- cumulative sum reaches 10 or higher: -- --
--   limitSummer :: Auto' Int (Int, Blip ())
--   limitSummer = (id &&& became (>= 10)) . sumFrom 0
--   
-- -- And now we throw it into resetFrom: -- --
--   resettingSummer :: Auto' Int Int
--   resettingSummer = resetFrom limitSummer
--   
-- --
--   >>> streamAuto' resettingSummer [1..10]
--   [ 1, 3, 6, 10    -- and...reset!
--   , 5, 11          -- and...reset!
--   , 7, 15          -- and...reset!
--   , 9, 19 ]
--   
resetFrom :: Monad m => Auto m a (b, Blip c) -> Auto m a b -- | This module provides Autos (purely) generating entropy in the -- form of random or noisy processes, as well as Autos to -- purify/seal Autos with underlying entropy. -- -- Note that every Auto and combinator here is completely -- deterministic --- given the same initial seed, one would expect the -- same stream of outputs on every run. Furthermore, if a serializable -- Auto is serialized and resumed, it will continue along the -- deterministic path dictated by the original seed given. -- -- All of these Autos and combinators come in three flavors: one -- serializing one that works with any serializable RandomGen -- instance, one serializing one that works specifically with -- StdGen from System.Random, and one that takes any -- RandomGen (including StdGen) and runs it without the -- ability to serialize and resume deterministically. -- -- The reason why there's a specialized StdGen version for all of -- these is that StdGen actually doesn't have a Serialize -- instance, so a rudimentary serialization process is provded with the -- StdGen versions. -- -- The first class of generators take arbitrary g -> (b, g) -- functions: "Generate a random b, using the given function, -- and replace the seed with the resulting seed". Most "random" functions -- follow this pattern, including random and randomR, and -- if you are using something from MonadRandom, then you can use -- the runRand function to turn a Rand g b into a -- g -> (b, g), as well: -- --
--   runRand :: RandomGen g => Rand g b -> (g -> (b, g))
--   
-- -- These are useful for generating noise...a new random value at every -- step. They are entropy sources. -- -- Alternatively, if you want to give up parallelizability and -- determinism and have your entire Auto be sequential, you can -- make your entire Auto run under Rand or RandT as -- its internal monad, from MonadRandom. -- --
--   Auto (Rand g) a b
--   Auto (RandT g m) a b
--   
-- -- In this case, if you wanted to pull a random number, you could do: -- --
--   effect random :: (Random r, RandomGen g) => Auto (Rand g) a r
--   effect random :: (Random r, RandomGen g) => Auto (RandT g m) a r
--   
-- -- Which pulls a random r from "thin air" (from the internal -- Rand monad). -- -- However, you lose a great deal of determinism from this method, as -- your Autos are no longer deterministic with a given seed...and -- resumability becomes dependent on starting everything with the same -- seed every time you re-load your Auto. Also, Auto's are -- parallelizable, while Auto (Rand g)s are not. -- -- As a compromise, you can then "seal" away the underlying monad with -- sealRandom, which takes an Auto (RandT g m) a -- b, a starting g, and turns it into a normal -- Auto m a b, with no underlying randomness monad. -- -- In this way, you can run any Auto under Rand or -- RandT as if it was a normal Auto "without" underlying -- randomness. This lets you compose your sequential/non-parallel parts -- in Rand...and the later, use it as a part of a -- parallelizable/potentially non-sequential Auto'. It's also -- convenient because you don't have to manually split and pass around -- seeds to every Auto that requires entropy. -- -- The other generators given are for useful random processes you might -- run into. The first is a Blip stream that emits at random times -- with the given frequencyprobability. The second works Interval/ -- semantics from Control.Auto.Interval, and is a stream that is -- "on" or "off", chunks at a time, for random lengths. The average -- length of each on or off period is controlled by the parameter you -- pass in. module Control.Auto.Process.Random -- | Given a seed-consuming generating function of form g -> (b, -- g) (where g is the seed, and b is the result) -- and an initial seed, return an Auto that continually generates -- random values using the given generating funcion. -- -- You'll notice that most of the useful functions from -- System.Random fit this form: -- --
--   random  :: RandomGen g =>            g -> (b, g)
--   randomR :: RandomGen g => (b, b) -> (g -> (b, g))
--   
-- -- If you are using something from MonadRandom, then you can use -- the runRand function to turn a Rand g b into a -- g -> (b, g): -- --
--   runRand :: RandomGen g => Rand g b -> (g -> (b, g))
--   
-- -- Here is an example using stdRands (for StdGen), but -- rands works exactly the same way, I promise! -- --
--   >>> let g = mkStdGen 8675309
--   
--   >>> let a = stdRands (randomR (1,100)) g :: Auto' a Int
--   
--   >>> let (res, _) = stepAutoN' 10 a ()
--   
--   >>> res
--   [67, 15, 97, 13, 55, 12, 34, 86, 57, 42]
--   
-- -- Yeah, if you are using StdGen from System.Random, you'll -- notice that StdGen has no Serialize instance, so you -- can't use it with this; you have to either use stdRands or -- rands_ (if you don't want serialization/resumability). -- -- In the context of these generators, resumability basically means -- deterministic behavior over re-loads...if "reloading", it'll ignore -- the seed you pass in, and use the original seed given when originally -- saved. rands :: (Serialize g, RandomGen g) => (g -> (b, g)) -> g -> Auto m a b -- | Like rands, but specialized for StdGen from -- System.Random, so that you can serialize and resume. This is -- needed because StdGen doesn't have a Serialize instance. -- -- See the documentation of rands for more information on this -- Auto. stdRands :: (StdGen -> (b, StdGen)) -> StdGen -> Auto m a b -- | The non-serializing/non-resuming version of rands. rands_ :: RandomGen g => (g -> (b, g)) -> g -> Auto m a b -- | Like rands, except taking a "monadic" random seed function -- g -> m (b, g), instead of g -> (b, g). Your -- random generating function has access to the underlying monad. -- -- If you are using something from MonadRandom, then you can use -- the runRandT function to turn a RandT g m b -- into a g -> m (b, g): -- --
--   runRandT :: (Monad m, RandomGen g)
--              => RandT g m b -> (g -> m (b, g))
--   
randsM :: (Serialize g, RandomGen g, Monad m) => (g -> m (b, g)) -> g -> Auto m a b -- | Like randsM, but specialized for StdGen from -- System.Random, so that you can serialize and resume. This is -- needed because StdGen doesn't have a Serialize instance. -- -- See the documentation of randsM for more information on this -- Auto. stdRandsM :: Monad m => (StdGen -> m (b, StdGen)) -> StdGen -> Auto m a b -- | The non-serializing/non-resuming version of randsM. randsM_ :: (RandomGen g, Monad m) => (g -> m (b, g)) -> g -> Auto m a b -- | Takes a "random function", or "random arrow" --- a function taking an -- input value and a starting seed/entropy generator and returning a -- result and an ending seed/entropy generator --- and turns it into an -- Auto that feeds its input into such a function and outputs the -- result, with a new seed every time. -- --
--   >>> let f x = randomR (0 :: Int, x)
--   
--   >>> streamAuto' (arrRandStd f (mkStdGen 782065)) [1..10]
--   -- [1,2,3,4,5,6,7,8,9,10] <- upper bounds
--      [1,2,0,1,5,3,7,6,8,10] -- random number from 0 to upper bound
--   
-- -- If you are using something from MonadRandom, then you can use -- the (runRand .) function to turn a a -> -- Rand g b into a a -> g -> (b, g): -- --
--   (runRand .) :: RandomGen g => (a -> Rand g b) -> (a -> g -> (b, g))
--   
-- -- (This is basically mkState, specialized.) arrRand :: (Serialize g, RandomGen g) => (a -> g -> (b, g)) -> g -> Auto m a b -- | Like arrRand, except the result is the result of a monadic -- action. Your random arrow function has access to the underlying monad. -- -- If you are using something from MonadRandom, then you can use -- the (runRandT .) function to turn a a -> -- RandT m g b into a a -> g -> m (b, g): -- --
--   (runRandT .) :: RandomGen g => (a -> RandT g b) -> (a -> g -> m (b, g))
--   
arrRandM :: (Monad m, Serialize g, RandomGen g) => (a -> g -> m (b, g)) -> g -> Auto m a b -- | Like arrRand, but specialized for StdGen from -- System.Random, so that you can serialize and resume. This is -- needed because StdGen doesn't have a Serialize instance. -- -- See the documentation of arrRand for more information on this -- Auto. arrRandStd :: (a -> StdGen -> (b, StdGen)) -> StdGen -> Auto m a b -- | Like arrRandM, but specialized for StdGen from -- System.Random, so that you can serialize and resume. This is -- needed because StdGen doesn't have a Serialize instance. -- -- See the documentation of arrRandM for more information on this -- Auto. arrRandStdM :: (a -> StdGen -> m (b, StdGen)) -> StdGen -> Auto m a b -- | The non-serializing/non-resuming version of arrRand. arrRand_ :: RandomGen g => (a -> g -> (b, g)) -> g -> Auto m a b -- | The non-serializing/non-resuming version of arrRandM. arrRandM_ :: RandomGen g => (a -> g -> m (b, g)) -> g -> Auto m a b -- | Simulates a Bernoulli Process: a process of sequential -- independent trials each with a success of probability p. -- -- Implemented here is an Auto producing a blip stream that emits -- whenever the bernoulli process succeeds with the value of the received -- input of the Auto, with its probability of succuss per each -- trial as the Double parameter. -- -- It is expected that, for probability p, the stream will emit -- a value on average once every 1/p ticks. bernoulli :: (Serialize g, RandomGen g) => Double -> g -> Auto m a (Blip a) -- | Like bernoulli, but specialized for StdGen from -- System.Random, so that you can serialize and resume. This is -- needed because StdGen doesn't have a Serialize instance. -- -- See the documentation of bernoulli for more information on this -- Auto. stdBernoulli :: Double -> StdGen -> Auto m a (Blip a) -- | The non-serializing/non-resuming version of bernoulli. bernoulli_ :: RandomGen g => Double -> g -> Auto m a (Blip a) -- | An Interval that is "on" and "off" for contiguous but random -- intervals of time...when "on", allows values to pass as "on" -- (Just), but when "off", suppresses all incoming values -- (outputing Nothing). -- -- You provide a Double, an l parameter, representing the -- averageexpected length of each onoff interval. -- -- The distribution of interval lengths follows a Geometric -- Distribution. This distribution is, as we call it in maths, -- "memoryless", which means that the "time left" that the Auto -- will be "on" or "off" at any given time is going to be, on average, -- the given l parameter. -- -- Internally, the "toggling" events follow a bernoulli process with a -- p parameter of 1 / l. randIntervals :: (Serialize g, RandomGen g) => Double -> g -> Interval m a a -- | Like randIntervals, but specialized for StdGen from -- System.Random, so that you can serialize and resume. This is -- needed because StdGen doesn't have a Serialize instance. -- -- See the documentation of randIntervals for more information on -- this Auto. stdRandIntervals :: Double -> StdGen -> Interval m a a -- | The non-serializing/non-resuming version of randIntervals. randIntervals_ :: RandomGen g => Double -> g -> Interval m a a -- | Takes an Auto over an Rand or RandT underlying -- monad as an entropy source, and "seals it away" to just be a normal -- Auto or Auto': -- --
--   sealRandom :: Auto (Rand g) a b -> g -> Auto' a b
--   
-- -- You can now compose your entropic Auto with other Autos -- (using ., and other combinators) as if it were a normal -- Auto. -- -- Useful because you can create entire programs that have access to an -- underlying entropy souce by composing with Rand...and then, at -- the end of it all, use/compose it with normal Autos as if it -- were a "pure" Auto. sealRandom :: (RandomGen g, Serialize g, Monad m) => Auto (RandT g m) a b -> g -> Auto m a b -- | Like sealRandom, but specialized for StdGen from -- System.Random, so that you can serialize and resume. This is -- needed because StdGen doesn't have a Serialize instance. -- -- See the documentation of sealRandom for more information on -- this combinator. sealRandomStd :: Monad m => Auto (RandT StdGen m) a b -> StdGen -> Auto m a b -- | The non-serializing/non-resuming version of sealRandom_. The -- random seed is not re-loaded/resumed, so every time you resume, the -- stream of available randomness begins afresh. sealRandom_ :: (RandomGen g, Monad m) => Auto (RandT g m) a b -> g -> Auto m a b -- | bernoulli, but uses an underlying entropy source -- (MonadRandom) to get its randomness from, instead of an -- initially passed seed. -- -- You can recover exactly bernoulli p by using -- sealRandom (bernoulliMR p). -- -- See sealRandom for more information. bernoulliMR :: MonadRandom m => Double -> Auto m a (Blip a) -- | randIntervals, but uses an underlying entropy source -- (MonadRandom) to get its randomness from, instead of an -- initially passed seed. -- -- You can recover exactly randIntervals l by using -- sealRandom (randIntervalsMR l). -- -- See sealRandom for more information. randIntervalsMR :: MonadRandom m => Double -> Interval m a a -- | This module serves as the main entry point for the library; these are -- all basically re-exports. The re-exports are chosen so you can start -- doing "normal things" off the bat, including all of the types used in -- this library. -- -- Conspicuously missing are the most of the tools for working with -- Interval, Blip streams, switches, and the "collection" -- autos; those are all pretty heavy, and if you do end up working with -- any of those tools, simply importing the appropriate module should -- give you all you need. -- -- See the tutorial if you need help getting started! module Control.Auto -- | The Auto type. For this library, an Auto semantically -- representsdenotes a a relationship/ between an input and an -- output that is preserved over multiple steps, where that relationship -- is (optionally) maintained within the context of a monad. -- -- A lot of fancy words, I know...but you can think of an Auto as -- nothing more than a "stream transformer" of value streams. A stream of -- sequential input values come in one at a time, and a stream of outputs -- pop out one at a time, as well. -- -- Using the streamAuto function, you can "unwrap" the inner -- value stream transformer from any Auto: if a :: Auto -- m a b, streamAuto lets you turn it into an [a] -> -- m [b]. "Give me a stream of as, one at a time, and I'll -- give you a list of bs, matching a relationship to your stream -- of as." -- --
--   -- unwrap your inner [a] -> m [b]!
--   streamAuto :: Monad m => Auto m a b -> ([a] -> m [b])
--   
-- -- You can also turn an Auto m a b into an effects -- stream that executes effects sequentially with -- toEffectStream and streamAutoEffects, so you can run -- it with a ListT-compatible library like pipes. -- -- There's a handy type synonym Auto' for relationships that don't -- really need a monadic context; the m is just Identity: -- --
--   type Auto' = Auto Identity
--   
-- -- So if you had an a :: Auto' a b, you can use -- streamAuto' to "unwrap" the inner stream transformer, [a] -- -> [b]. -- --
--   -- unwrap your inner [a] -> [b]!
--   streamAuto' :: Auto' a b -> ([a] -> [b])
--   
-- -- All of the Autos given in this library maintain some sort of -- semantic relationship between streams --- for some, the outputs might -- be the inputs with a function applied; for others, the outputs might -- be the cumulative sum of the inputs. -- -- See the tutorial for more information! -- -- Operationally, an Auto m a b is implemented as a -- "stateful function". A function from an a where, every time -- you "apply" it, you get a b and an "updated -- Auto"/function with updated state. -- -- You can get this function using stepAuto: -- --
--   stepAuto :: Auto m a b -> (a -> m (b, Auto m a b))
--   
-- -- Or, for Auto', stepAuto': -- --
--   stepAuto' :: Auto' a b -> (a -> (b, Auto' a b))
--   
-- -- "Give me an a and I'll give you a b and your -- "updated" Auto". -- -- Autos really are mostly useful because they can be composed, -- chained, and modified using their various typeclass instances, like -- Category, Applicative, Functor, Arrow, -- etc., and also with the combinators in this library. You can build -- complex programs as a complex Auto by building up smaller and -- smaller components. See the tutorial for more information on this. -- -- This type also contains information on its own serialization, so you -- can serialize and re-load the internal state to binary or disk. See -- the "serialization" section in the documentation for -- Control.Auto.Core, or the documentation for mkAutoM for -- more details. data Auto m a b -- | Special case of Auto where the underlying Monad is -- Identity. -- -- Instead of "wrapping" an [a] -> m [b], it "wraps" an -- [a] -> [b]. type Auto' = Auto Identity -- | When used in the context of an input or output of an Auto, a -- Blip a represents a stream that occasionally, at -- "independent" or "discrete" points, emits a value of type a. -- -- Contrast this to Interval, where things are meant to be "on" -- or "off" for contiguous chunks at a time; blip streams are "blippy", -- and Intervals are "chunky". -- -- It's here mainly because it's a pretty useful abstraction in the -- context of the many combinators found in various modules of this -- library. If you think of an Auto m a (Blip b) -- as producing a "blip stream", then there are various combinators and -- functions that are specifically designed to manipulate blip streams. -- -- For the purposes of the semantics of what Blip is supposed to -- represent, its constructors are hidden. (Almost) all of the various -- Blip combinators (and its very useful Functor instance) -- "preserve Blipness" --- one-at-a-time occurrences remain -- one-at-a-time under all of these combinators, and you should have -- enough so that direct access to the constructor is not needed. -- -- If you are creating a framework, library, or backend, you might want -- to manually create blip stream-producing Autos for your users -- to access. In this case, you can import the constructors and useful -- internal (and, of course, semantically unsafe) functions from -- Control.Auto.Blip.Internal. data Blip a -- | Represents a relationship between an input and an output, where the -- output can be "on" or "off" (using Just and Nothing) for -- contiguous chunks of time. -- -- "Just" a type alias for Auto m a (Maybe b). If -- you ended up here with a link...no worries! If you see -- Interval m a b, just think Auto m a -- (Maybe b) for type inference/type checking purposes. -- -- If you see something of type Interval, you can rest assured -- that it has "interval semantics" --- it is on and off for meaningfully -- contiguous chunks of time, instead of just on and off willy nilly. If -- you have a function that expects an Interval, then the function -- expects its argument to behave in this way. type Interval m a b = Auto m a (Maybe b) -- | Interval, specialized with Identity as its underlying -- Monad. Analogous to Auto' for Auto. type Interval' a b = Auto' a (Maybe b) -- | Runs the Auto through one step. -- -- That is, given an Auto m a b, returns a function that -- takes an a and returns a b and an "updated"/"next" -- Auto; an a -> m (b, Auto m a b). -- -- This is the main way of running an Auto "step by step", so if -- you have some sort of game loop that updates everything every "tick", -- this is what you're looking for. At every loop, gather input -- a, feed it into the Auto, "render" the result -- b, and get your new Auto to run the next time. -- -- Here is an example with sumFrom 0, the Auto -- whose output is the cumulative sum of the inputs, and an underying -- monad of Identity. Here, -- --
--   stepAuto :: Auto Identity Int Int
--            -> (Int -> Identity (Int, Auto Identity Int Int))
--   
-- -- Every time you "step", you give it an Int and get a resulting -- Int (the cumulative sum) and the "updated Auto", with -- the updated accumulator. -- --
--   >>> let a0 :: Auto Identity Int Int
--           a0 = sumFrom 0
--   
--   >>> let Identity (res1, a1) = stepAuto a0 4      -- run with 4
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> let Identity (res2, a2) = stepAuto a1 5      -- run with 5
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> let Identity (res3, _ ) = stepAuto a2 3      -- run with 3
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- By the way, for the case where your Auto is under -- Identity, we have a type synomym Auto'...and a -- convenience function to make "running" it more streamlined: -- --
--   >>> let a0 :: Auto' Int Int
--           a0 = sumFrom 0
--   
--   >>> let (res1, a1) = stepAuto' a0 4          -- run with 4
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> let (res2, a2) = stepAuto' a1 5          -- run with 5
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> let (res3, _ ) = stepAuto' a2 3          -- run with 3
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- But, if your Auto actaully has effects when being stepped, -- stepAuto will execute them: -- --
--   >>> let a0 :: Auto IO Int Int
--           a0 = effect (putStrLn "hey!") *> sumFrom 0
--   
--   >>> (res1, a1) <- stepAuto a0 4              -- run with 4
--   hey!         -- IO effect
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> (res2, a2) <- stepAuto a1 5              -- run with 5
--   hey!         -- IO effect
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> (res3, _ ) <- stepAuto a2 3              -- run with 3
--   hey!         -- IO effect
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- (Here, effect (putStrLn "hey") is an -- Auto IO Int (), which ignores its input and just -- executes putStrLn "hey" every time it is run. When we -- use *> from Control.Applicative, we "combine" the two -- Autos together and run them both on each input (4, 5, -- 3...)...but for the "final" output at the end, we only return the -- output of the second one, sumFrom 0 (5, 9, 12...)) -- -- If you think of an Auto m a b as a "stateful function" -- a -> m b, then stepAuto lets you "run" it. -- -- In order to directly run an Auto on a stream, an [a], -- use streamAuto. That gives you an [a] -> m [b]. stepAuto :: Monad m => Auto m a b -> a -> m (b, Auto m a b) -- | Runs an Auto' through one step. -- -- That is, given an Auto' a b, returns a function that -- takes an a and returns a b and an "updated"/"next" -- Auto'; an a -> (b, Auto' a b). -- -- See stepAuto documentation for motivations, use cases, and more -- details. You can use this instead of stepAuto when your -- underyling monad is Identity, and your Auto doesn't -- produce any effects. -- -- Here is an example with sumFrom 0, the Auto' -- whose output is the cumulative sum of the inputs -- --
--   stepAuto' :: Auto' Int Int
--             -> (Int -> (Int, Auto' Int Int))
--   
-- -- Every time you "step", you give it an Int and get a resulting -- Int (the cumulative sum) and the "updated Auto'", with -- the updated accumulator. -- --
--   >>> let a0 :: Auto' Int Int
--           a0 = sumFrom 0
--   
--   >>> let (res1, a1) = stepAuto' a0 4          -- run with 4
--   
--   >>> res1
--   4                -- the cumulative sum, 4
--   
--   >>> let (res2, a2) = stepAuto' a1 5          -- run with 5
--   
--   >>> res2
--   9                -- the cumulative sum, 4 + 5
--   
--   >>> let (res3, _ ) = stepAuto' a2 3          -- run with 3
--   
--   >>> res3
--   12               -- the cumulative sum, 4 + 5 + 3
--   
-- -- If you think of an Auto' a b as a "stateful function" -- a -> b, then stepAuto' lets you "run" it. -- -- In order to directly run an Auto' on a stream, an [a], -- use streamAuto'. That gives you an [a] -> [b]. stepAuto' :: Auto' a b -> a -> (b, Auto' a b) -- | Like stepAuto, but drops the "next Auto" and just gives -- the result. evalAuto :: Monad m => Auto m a b -> a -> m b -- | Like stepAuto', but drops the "next Auto'" and just -- gives the result. evalAuto for Auto'. evalAuto' :: Auto' a b -> a -> b -- | Stream an Auto over a list, returning the list of results. Does -- this "lazily" (over the Monad), so with most Monads, this should work -- fine with infinite lists. (That is, streamAuto -- (arrM f) behaves exactly like mapM f, -- and you can reason with Autos as if you'd reason with -- mapM on an infinite list) -- -- Note that, conceptually, this turns an Auto m a b into -- an [a] -> m [b]. -- -- See streamAuto' for a simpler example; here is one taking -- advantage of monadic effects: -- --
--   >>> let a = arrM print *> sumFrom 0 :: Auto IO Int Int
--   
--   >>> ys <- streamAuto a [1..5]
--   1                -- IO effects
--   2
--   3
--   4
--   5
--   
--   >>> ys
--   [1,3,6,10,15]    -- the result
--   
-- -- a here is like sumFrom 0, except at every -- step, prints the input item to stdout as a side-effect. -- -- Note that we use "stream" here slightly differently than in libraries -- like pipes or conduit. We don't stream over the -- m Monad (like IO)...we stream over the input -- elements. Using streamAuto on an infinite list allows you -- to "stop", for example, to find the result...but it will still -- sequence all the *effects*. -- -- For example: -- --
--   >>> take 10 <$> streamAuto (arrM print *> id) [1..]
--   
-- -- Will execute print on every element before "returning" with -- [1..10]. -- --
--   >>> flip runState 0 $ take 10 <$> streamAuto (arrM (modify . (+)) *> id) [1..]
--   ([1,2,3,4,5,6,7,8,9,10], .... (never terminates)
--   
-- -- This will immediately return the "result", and you can bind to the -- result with `(>>=)`, but it'll never return a "final state", -- because the final state involves executing all of the modifys. -- -- In other words, we stream values, not effects. You would -- analyze this behavior the same way you would look at something like -- mapM. -- -- If you want to stream effects, you can use streamAutoEffects or -- toEffectStream, and use an effects streaming library like -- pipes (or anything with ListT)...this will give the -- proper streaming of effects with resource handling, handling infinite -- streams in finite space with finite effects, etc. streamAuto :: Monad m => Auto m a b -> [a] -> m [b] -- | Stream an Auto' over a list, returning the list of results. -- Does this lazily, so this should work fine with (and is actually -- somewhat designed for) infinite lists. -- -- Note that conceptually this turns an Auto' a b into an -- [a] -> [b] -- --
--   >>> streamAuto' (arr (+3)) [1..10]
--   [4,5,6,7,8,9,10,11,12,13]
--   
--   >>> streamAuto' (sumFrom 0) [1..5]
--   [1,3,6,10,15]
--   
--   >>> streamAuto' (productFrom 1) . streamAuto' (sumFrom 0) $ [1..5]
--   [1,3,18,180,2700]
--   
--   >>> streamAuto' (productFrom 1 . sumFrom 0) $ [1..5]
--   [1,3,18,180,2700]
--   
--   >>> streamAuto' id [1..5]
--   [1,2,3,4,5]
--   
streamAuto' :: Auto' a b -> [a] -> [b] -- | Streams (in the context of the underlying monad) the given Auto -- with a stream of constant values as input, a given number of times. -- After the given number of inputs, returns the list of results and the -- next/updated Auto, in the context of the underlying monad. -- --
--   stepAutoN n a0 x = overList a0 (replicate n x)
--   
-- -- See stepAutoN' for a simpler example; here is one taking -- advantage of monadic effects: -- --
--   >>> let a = arrM print *> sumFrom 0 :: Auto IO Int Int
--   
--   >>> (ys, a') <- stepAutoN 5 a 3
--   3                -- IO effects
--   3
--   3
--   3
--   3
--   
--   >>> ys
--   [3,6,9,12,15]    -- the result
--   
--   >>> (ys'', _) <- stepAutoN 5 a' 5
--   5                -- IO effects
--   5
--   5
--   5
--   5
--   
--   >>> ys''
--   [20,25,30,35,50] -- the result
--   
-- -- a here is like sumFrom 0, except at every -- step, prints the input item to stdout as a side-effect. stepAutoN :: Monad m => Int -> Auto m a b -> a -> m ([b], Auto m a b) -- | Streams the given Auto' with a stream of constant values as -- input, a given number of times. After the given number of inputs, -- returns the list of results and the next/updated Auto. -- --
--   stepAutoN' n a0 x = overList' a0 (replicate n x)
--   
-- --
--   >>> let (ys, a') = stepAutoN' 5 (sumFrom 0) 3
--   
--   >>> ys
--   [3,6,9,12,15]
--   
--   >>> let (ys', _) = stepAutoN' 5 a' 5
--   
--   >>> ys'
--   [20,25,30,35,40]
--   
stepAutoN' :: Int -> Auto' a b -> a -> ([b], Auto' a b) -- | Encode an Auto and its internal state into a ByteString. encodeAuto :: Auto m a b -> ByteString -- | Resume an Auto from its ByteString serialization, -- giving a Left if the deserialization is not possible. decodeAuto :: Auto m a b -> ByteString -> Either String (Auto m a b) -- | Give a FilePath and an Auto, and readAuto will -- attempt to resume the saved state of the Auto from disk, -- reading from the given FilePath. Will return Left upon a -- decoding error, with the error, and Right if the decoding is -- succesful. readAuto :: FilePath -> Auto m a b -> IO (Either String (Auto m a b)) -- | Given a FilePath and an Auto, serialize and freeze the -- state of the Auto as binary to that FilePath. writeAuto :: FilePath -> Auto m a b -> IO () -- | Takes an Auto that is serializable/resumable and returns an -- Auto that is not. That is, when it is "saved", saves no data, -- and when it is "resumed", resets itself back to the initial -- configuration every time; in other words, decodeAuto -- (unserialize a) bs = Right (unserialize a). Trying to "resume" it -- will just always give itself, unchanged. unserialize :: Monad m => Auto m a b -> Auto m a b -- | A special Auto that acts like the id Auto, but -- forces results as they come through to be fully evaluated, when -- composed with other Autos. -- -- TODO: Test if this really works forcer :: NFData a => Auto m a a -- | A special Auto that acts like the id Auto, but -- forces results as they come through to be evaluated to Weak Head -- Normal Form, with seq, when composed with other Autos. -- -- TODO: Test if this really works seqer :: Auto m a a -- | Swaps out the underlying Monad of an Auto using the -- given monad morphism "transforming function", a natural -- transformation. -- -- Basically, given a function to "swap out" any m a with an -- m' a, it swaps out the underlying monad of the Auto. -- -- This forms a functor, so you rest assured in things like this: -- --
--   hoistA id == id
--   hoistA f a1 . hoistA f a2 == hoistA f (a1 . a2)
--   
hoistA :: (Monad m, Monad m') => (forall c. m c -> m' c) -> Auto m a b -> Auto m' a b -- | Generalizes an Auto' a b to an Auto m a -- b' for any Monad m, using hoist. -- -- You generally should be able to avoid using this if you never directly -- write any Auto's and always write 'Auto m' parameterized over -- all Monads, but...in case you import one from a library or -- something, you can use this. generalizeA :: Monad m => Auto' a b -> Auto m a b -- | Applies the given "monadic function" (function returning a monadic -- action) to every incoming item; the result is the result of executing -- the action returned. -- -- Note that this essentially lifts a "Kleisli arrow"; it's like -- arr, but for "monadic functions" instead of normal functions: -- --
--   arr  :: (a -> b)   -> Auto m a b
--   arrM :: (a -> m b) -> Auto m a b
--   
-- --
--   arrM f . arrM g == arrM (f <=< g)
--   
-- -- One neat trick you can do is that you can "tag on effects" to a normal -- Auto by using *> from Control.Applicative. For -- example: -- --
--   >>> let a = arrM print *> sumFrom 0
--   
--   >>> ys <- streamAuto a [1..5]
--   1                -- IO output
--   2
--   3
--   4
--   5
--   
--   >>> ys
--   [1,3,6,10,15]    -- the result
--   
-- -- Here, a behaves "just like" sumFrom -- 0...except, when you step it, it prints out to stdout as a -- side-effect. We just gave automatic stdout logging behavior! arrM :: (a -> m b) -> Auto m a b -- | Like arr, but applies the function to the previous value -- of the input, instead of the current value. Used for the same purposes -- as lastVal: to manage recursive bindings. -- -- Warning: Don't use this to do imperative programming! -- --
--   arrD id == lastVal
--   
-- --
--   >>> streamAuto' (arrD negate 100) [1..10]
--   [100,-1,-2,-3,-4,-5,-6,-7,-8,-9]
--   
arrD :: Serialize b => (a -> b) -> b -> Auto m a b -- | Construct an Auto from a "folding" function: b -> a -- -> b yields an Auto m a b. Basically acts like -- a foldl or a scanl. There is an internal accumulator -- that is "updated" with an a at every step. Must be given an -- initial accumulator. -- -- Example: an Auto that sums up all of its input. -- --
--   >>> let summer = accum (+) 0
--   
--   >>> let (sum1, summer')  = stepAuto' summer 3
--   
--   >>> sum1
--   3
--   
--   >>> let (sum2, summer'') = stepAuto' summer' 10
--   
--   >>> sum2
--   13
--   
--   >>> streamAuto'  summer'' [1..10]
--   [14,16,19,23,28,34,41,49,58,68]
--   
-- -- If your accumulator b does not have a Serialize -- instance, then you should either write a meaningful one, or throw away -- serializability and use accum_. accum :: Serialize b => (b -> a -> b) -> b -> Auto m a b -- | A version of accum, where the internal accumulator isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See accum for more details. -- -- Useful if your accumulator b cannot have a meaningful -- Serialize instance. accum_ :: (b -> a -> b) -> b -> Auto m a b -- | Construct an Auto from a "monadic" "folding" function: b -- -> a -> m b yields an Auto m a b. Basically -- acts like a foldM or scanM (if it existed). here is an -- internal accumulator that is "updated" with an input a with -- the result of the executed m b at every step. Must be given -- an initial accumulator. -- -- See accum for more details. -- -- If your accumulator b does not have a Serialize -- instance, then you should either write a meaningful one, or throw away -- serializability and use accumM_. accumM :: (Serialize b, Monad m) => (b -> a -> m b) -> b -> Auto m a b -- | A version of 'accumM_, where the internal accumulator isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See accumM for more details. -- -- Useful if your accumulator b cannot have a meaningful -- Serialize instance. accumM_ :: Monad m => (b -> a -> m b) -> b -> Auto m a b -- | A "delayed" version of accum, where the first output is the -- initial state of the accumulator, before applying the folding -- function. Useful in recursive bindings. -- --
--   >>> let summerD = accumD (+) 0
--   
--   >>> let (sum1, summerD')  = stepAuto' summerD 3
--   
--   >>> sum1
--   0
--   
--   >>> let (sum2, summerD'') = stepAuto' summerD' 10
--   
--   >>> sum2
--   3
--   
--   >>> streamAuto'  summerD'' [1..10]
--   [13,14,16,19,23,28,34,41,49,58]
--   
-- -- (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) -> b -> Auto m a b -- | The non-resuming/non-serializing version of accumD. accumD_ :: (b -> a -> b) -> b -> Auto m a b -- | A "delayed" version of accumM, where the first output is the -- initial state of the accumulator, before applying the folding -- function. Useful in recursive bindings. accumMD :: (Serialize b, Monad m) => (b -> a -> m b) -> b -> Auto m a b -- | The non-resuming/non-serializing version of accumMD. accumMD_ :: Monad m => (b -> a -> m b) -> b -> Auto m a b -- | Construct an Auto from a state transformer: an a -> s -- -> (b, s) gives you an Auto m a b, for any -- Monad m. At every step, it takes in the a -- input, runs the function with the stored internal state, returns the -- b result, and now contains the new resulting state. You have -- to intialize it with an initial state, of course. -- -- From the "stream transformer" point of view, this is rougly equivalent -- to mapAccumL from Data.List, with the function's -- arguments and results in the backwards order. -- --
--   streamAuto' (mkState f s0) = snd . mapAccumL (\s x -> swap (f x s))
--   
-- -- Try not to use this if it's ever avoidable, unless you're a framework -- developer or something. Try make something by combining/composing the -- various Auto combinators. -- -- If your state s does not have a Serialize instance, -- then you should either write a meaningful one, provide the -- serialization methods manually with mkState', or throw away -- serializability and use mkState_. mkState :: Serialize s => (a -> s -> (b, s)) -> s -> Auto m a b -- | Construct an Auto from a "monadic" state transformer: a -- -> s -> m (b, s) gives you an Auto m a b. -- At every step, it takes in the a input, runs the function -- with the stored internal state and "executes" the m (b, s) to -- get the b output, and stores the s as the new, -- updated state. Must be initialized with an initial state. -- -- Try not to use this if it's ever avoidable, unless you're a framework -- developer or something. Try make something by combining/composing the -- various Auto combinators. -- -- This version is a wrapper around mkAuto, that keeps track of -- the serialization and re-loading of the internal state for you, so you -- don't have to deal with it explicitly. -- -- If your state s does not have a Serialize instance, -- then you should either write a meaningful one, provide the -- serialization methods manually with mkStateM', or throw away -- serializability and use mkStateM_. mkStateM :: Serialize s => (a -> s -> m (b, s)) -> s -> Auto m a b -- | A version of mkState, where the internal state isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See mkState for more details. -- -- Useful if your state s cannot have a meaningful -- Serialize instance. mkState_ :: (a -> s -> (b, s)) -> s -> Auto m a b -- | A version of mkStateM, where the internal state isn't -- serialized. It can be "saved" and "loaded", but the state is lost in -- the process. -- -- See mkStateM for more details. -- -- Useful if your state s cannot have a meaningful -- Serialize instance. mkStateM_ :: (a -> s -> m (b, s)) -> s -> Auto m a b -- | To get every output, executes the monadic action and returns the -- result as the output. Always ignores input. -- -- This is basically like an "effectful" pure: -- --
--   pure   :: b   -> Auto m a b
--   effect :: m b -> Auto m a b
--   
-- -- The output of pure is always the same, and the output of -- effect is always the result of the same monadic action. Both -- ignore their inputs. -- -- Fun times when the underling Monad is, for instance, -- Reader. -- --
--   >>> let a = effect ask    :: Auto (Reader b) a b
--   
--   >>> let r = evalAuto a () :: Reader b b
--   
--   >>> runReader r "hello"
--   "hello"
--   
--   >>> runReader r 100
--   100
--   
-- -- If your underling monad has effects (IO, State, -- Maybe, Writer, etc.), then it might be fun to take -- advantage of *> from Control.Applicative to "tack on" -- an effect to a normal Auto: -- --
--   >>> let a = effect (modify (+1)) *> sumFrom 0 :: Auto (State Int) Int Int
--   
--   >>> let st = streamAuto a [1..10]
--   
--   >>> let (ys, s') = runState st 0
--   
--   >>> ys
--   [1,3,6,10,15,21,28,36,45,55]
--   
--   >>> s'
--   10
--   
-- -- Our Auto a behaves exactly like sumFrom -- 0, except at each step, it also increments the underlying/global -- state by one. It is sumFrom 0 with an "attached -- effect". effect :: m b -> Auto m a b -- | Analogous to iterate from Prelude. Keeps accumulator -- value and continually applies the function to the accumulator at every -- step, outputting the result. -- -- The first result is the initial accumulator value. -- --
--   >>> take 10 . streamAuto' (iterator (*2) 1) $ repeat ()
--   [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
--   
iterator :: Serialize b => (b -> b) -> b -> Auto m a b -- | The non-resuming/non-serializing version of iterator. iterator_ :: (b -> b) -> b -> Auto m a b -- | Like iterator, but with a monadic function. iteratorM :: (Serialize b, Monad m) => (b -> m b) -> b -> Auto m a b -- | The non-resuming/non-serializing version of iteratorM. iteratorM_ :: Monad m => (b -> m b) -> b -> Auto m a b -- | The stream of outputs is the cumulative/running sum of the inputs so -- far, starting with an initial count. -- -- The first output takes into account the first input. See -- sumFromD for a version where the first output is the initial -- count itself. -- --
--   sumFrom x0 = accum (+) x0
--   
sumFrom :: (Serialize a, Num a) => a -> Auto m a a -- | The non-resuming/non-serializing version of sumFrom. sumFrom_ :: Num a => a -> Auto m a a -- | Like sumFrom, except the first output is the starting count. -- --
--   >>> let a = sumFromD 5
--   
--   >>> let (y1, a') = stepAuto' a 10
--   
--   >>> y1
--   5
--   
--   >>> let (y2, _ ) = stepAuto' a' 3
--   
--   >>> y2
--   10
--   
-- --
--   >>> streamAuto' (sumFrom 0) [1..10]
--   [1,3,6,10,15,21,28,36,45,55]
--   
--   >>> streamAuto' (sumFromD 0) [1..10]
--   [0,1,3,6,10,15,21,28,36,45]
--   
-- -- It's sumFrom, but "delayed". -- -- Useful for recursive bindings, where you need at least one value to be -- able to produce its "first output" without depending on anything else. -- --
--   sumFromD x0 = sumFrom x0 . delay 0
--   
-- --
--   sumFromD x0 = delay x0 . sumFrom x0
--   
sumFromD :: (Serialize a, Num a) => a -> Auto m a a -- | The non-resuming/non-serializing version of sumFromD. sumFromD_ :: Num a => a -> Auto m a a -- | The output is the running/cumulative product of all of the inputs so -- far, starting from an initial product. -- --
--   productFrom x0 = accum (*) x0
--   
productFrom :: (Serialize a, Num a) => a -> Auto m a a -- | The non-resuming/non-serializing version of productFrom. productFrom_ :: Num a => a -> Auto m a a -- | The output is the running/cumulative mconcat of all of the -- input seen so far, starting with mempty. -- --
--   >>> streamauto' mappender . map Last $ [Just 4, Nothing, Just 2, Just 3]
--   [Last (Just 4), Last (Just 4), Last (Just 2), Last (Just 3)]
--   
--   >>> streamAuto' mappender ["hello","world","good","bye"]
--   ["hello","helloworld","helloworldgood","helloworldgoodbye"]
--   
-- --
--   mappender = accum mappend mempty
--   
mappender :: (Serialize a, Monoid a) => Auto m a a -- | The non-resuming/non-serializing version of mappender. mappender_ :: Monoid a => Auto m a a -- | The output is the running <>-sum (mappend for -- Semigroup) of all of the input values so far, starting with a -- given starting value. Basically like mappender, but with a -- starting value. -- --
--   >>> streamAuto' (mappendFrom (Max 0)) [Max 4, Max (-2), Max 3, Max 10]
--   [Max 4, Max 4, Max 4, Max 10]
--   
-- --
--   mappendFrom m0 = accum (<>) m0
--   
mappendFrom :: (Serialize a, Semigroup a) => a -> Auto m a a -- | An Auto that returns the last value received by it. Given an -- "initial value" to output first. -- -- From the signal processing world, this is known as the "lag operator" -- L. -- -- This is (potentially) a very dangerous Auto, because its -- usage and its very existence opens the door to breaking -- denotative/declarative style and devolving into imperative style -- coding. However, when used where it is supposed to be used, it is more -- or less invaluable, and will be an essential part of many programs. -- -- Its main usage is for dealing with recursive bindings. If you ever are -- laying out recursive bindings in a high-level/denotative way, you need -- to have at least one value be able to have a "initial output" without -- depending on anything else. lastVal and delay allow you -- to do this. -- -- See the recursive example for more information on the -- appropriate usage of lastVal and delay. -- --
--   >>> streamAuto' (lastVal 100) [1..10]
--   [100,1,2,3,4,5,6,7,8,9]
--   
lastVal :: Serialize a => a -> Auto m a a -- | The non-resuming/non-serializing version of lastVal. lastVal_ :: a -> Auto m a a -- | An alias for lastVal; used in contexts where "delay" is more a -- meaningful description than "last value". All of the warnings for -- lastVal still apply, so you should probably read it if you -- haven't :) delay :: Serialize a => a -> Auto m a a -- | The non-resuming/non-serializing version of delay. delay_ :: a -> Auto m a a -- | A simple Auto that ignores all input; its output stream counts -- upwards from zero. -- --
--   >>> take 10 . streamAuto' count $ repeat ()
--   [0,1,2,3,4,5,6,7,8,9]
--   
count :: (Serialize b, Num b) => Auto m a b -- | "This, then that". Behave like the first Interval (and run its -- effects) as long as it is "on" (outputting Just). As soon as it -- turns off (is Nothing), it'll "switch over" and begin behaving -- like the second Auto forever, running the effects of the second -- Auto, too. Works well if the Autos follow interval -- semantics from Control.Auto.Interval. -- --
--   >>> let a1 = whenI (<= 4) --> pure 0
--   
--   >>> streamAuto' a1 [1..10]
--   [1, 2, 3, 4, 0, 0, 0, 0, 0, 0]
--   
-- -- (whenI only lets items satisfying the predicate pass through as -- "on", and is "off" otherwise; pure is the Auto that -- always produces the same output) -- -- Association works in a way that you can "chain" -->s, as -- long as you have an appropriate Auto (and not Interval) -- at the end: -- --
--   >>> let a2 = onFor 3 . sumFrom 0
--            --> onFor 3 . sumFrom 100
--            --> pure 0
--   
--   >>> streamAuto' a2 [1..10]
--   [1,3,6,104,109,115,0,0,0,0]
--   
-- -- a --> b --> c associates as a --> (b --> -- c) -- -- This is pretty invaluable for having Autos "step" through a -- series of different Autos, progressing their state from one -- stage to the next. Autos can control when they want to be -- "moved on" from by turning "off" (outputting Nothing). -- -- Note that recursive bindings work just fine, so: -- --
--   >>> let a3 = onFor 2 . pure "hello"
--            --> onFor 2 . pure "world"
--            --> a3
--   
--   >>> let (res3, _) = stepAutoN' 8 a3 ()
--   
--   >>> res3
--   ["hello", "hello", "world", "world", "hello", "hello", "world", "world"]
--   
-- -- the above represents an infinite loop between outputting "hello" and -- outputting "world". -- -- For serialization, an extra byte cost is incurred per invocation of -- -->. For cyclic switches like a3, every time the -- cycle "completes", it adds another layer of --> byte costs. -- For example, initially, saving a3 incurs a cost for the two -- -->s. After a3 loops once, it incurs a cost for -- another two -->s, so it costs four -->s. After -- a3 loops another time, it is like a cost of six -- -->s. So be aware that for cyclic bindings like a3, -- space for serialization grows at O(n). -- -- By the way, it might be worth contrasting this with <|!> -- and <|?> from Control.Auto.Interval, which have -- the same type signatures. Those alternative-y operators always feed -- the input to both sides, run both sides, and output the -- first Just. With <|!>, you can "switch back and -- forth" to the first Auto as soon as the first Auto is -- "on" (Just) again. -- -- -->, in contrast, runs only the first Auto -- until it is off (Nothing)...then runs only the second -- Auto. This transition is one-way, as well. (-->) :: Monad m => Interval m a b -> Auto m a b -> Auto m a b -- | A variation of -->, where the right hand side can also be an -- Interval / Maybe. The entire result is, then, a -- Maybe. Probably less useful than --> in most -- situations. (-?>) :: Monad m => Interval m a b -> Interval m a b -> Interval m a b -- | An Auto that runs every input through a a -> -- Maybe b test and produces a blip stream that emits the -- value inside every Just result. -- -- Particularly useful with prisms from the lens package, where -- things like emitJusts (preview _Right) will emit the -- b whenever the input Either a b stream is a -- Right. -- -- Warning! Carries all of the same dangers of emitOn. You can -- easily break blip semantics with this if you aren't sure what you are -- doing. Remember to only emit at discrete, separate occurences, and not -- for interval-like (on and off for chunks at a time) things. For -- interval semantics, we have Control.Auto.Interval. -- -- See the examples of emitOn for more concrete good/bad use -- cases. emitJusts :: (a -> Maybe b) -> Auto m a (Blip b) -- | Produces a blip stream that emits the input value whenever the input -- satisfies a given predicate. -- -- Warning! This Auto has the capability of "breaking" blip -- semantics. Be sure you know what you are doing when using this. Blip -- streams are semantically supposed to only emit at discrete, separate -- occurrences. Do not use this for interval-like (on and off for chunks -- at a time) things; each input should be dealt with as a separate -- thing. -- -- For interval semantics, we have Interval from -- Control.Auto.Interval. -- -- Good example: -- --
--   -- is only emitting at discrete blips
--   emitOn even . iterator (+ 1) 0
--   
-- -- Bad examples: -- --
--   -- is emitting for "durations" or "intervals" of time.
--   emitOn (< 10) . iterator (+ 1) 0
--   
--   emitOn (const True) . foo
--   
-- -- These bad examples would be good use cases of Interval. -- -- Can be particularly useful with prisms from the lens package, -- where things like emitOn (has _Right) and emitOn (hasn't -- _Right) will emit the input Either a b whenever it is or -- isn't a Right. See emitJusts for more common uses with -- lens. emitOn :: (a -> Bool) -> Auto m a (Blip a) -- | 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 -> Auto m (Blip a) a -- | fromBlipsWith d f is an Auto that decomposes -- the incoming blip stream by constantly outputting d except -- when the stream emits, and outputs the result of applying f -- to the emitted value when it does. fromBlipsWith :: b -> (a -> b) -> Auto m (Blip a) b -- | holdWith y0 is an Auto whose output is always -- the /most recently emitted/ value from the input blip stream. Before -- anything is emitted, y0 is outputted as a placeholder. -- -- Contrast with hold from Control.Auto.Interval. holdWith :: Serialize a => a -> Auto m (Blip a) a -- | A non-serializing/non-resumable version of holdWith. holdWith_ :: a -> Auto m (Blip a) a -- | Takes an Auto m a b (an Auto that turns -- incoming as into outputting bs) into an -- Auto m (Blip a) (Blip b); the original -- Auto is lifted to only be applied to emitted contents of a blip -- stream. -- -- When the stream emits, the original Auto is "stepped" with the -- emitted value; when it does not, it is paused and frozen until the -- next emission. -- --
--   >>> let sums = perBlip (sumFrom 0)
--   
--   >>> let blps = eachAt 2 [1,5,2]
--   
--   >>> take 8 . streamAuto' blps $ repeat ()
--   [NoBlip, Blip 1, NoBlip, Blip 5, NoBlip, Blip 2, NoBlip, NoBlip]
--   
--   >>> take 8 . streamAuto' (sums . blps) $ repeat ()
--   [NoBlip, Blip 1, NoBlip, Blip 6, NoBlip, Blip 8, NoBlip, NoBlip]
--   
perBlip :: Monad m => Auto m a b -> Auto m (Blip a) (Blip b) -- | An Auto that ignores its input and produces a blip stream never -- emits. never :: Auto m a (Blip b) -- | Produces a blip stream that emits with the first received input value, -- and never again after that. -- -- Often used with pure: -- --
--   immediately . pure "Emit me!"
--   
-- -- Or, in proc notation: -- --
--   blp <- immediately -< "Emit me!"
--   
-- -- to get a blip stream that emits a given value (eg., "Emit me!") once -- and stops emitting ever again. -- --
--   >>> streamAuto' (immediately . pure "Emit me!") [1..5]
--   [Blip "Emit Me!", NoBlip, NoBlip, NoBlip, NoBlip]
--   
immediately :: Auto m a (Blip a) -- | For onFor n, the first n items in the output -- stream are always "on" (passing through with exactly the value of the -- corresponding input); for the rest, the output stream is always "off", -- suppressing all input values forevermore. -- -- If a number less than 0 is passed, 0 is used. onFor :: Int -> Interval m a a -- | Lifts an Auto m a b (transforming as -- into bs) into an Auto m (Maybe a) -- (Maybe b) (or, Interval m (Maybe a) -- b, transforming intervals of as into -- intervals of b. -- -- It does this by running the Auto as normal when the input is -- "on", and freezing itbeing "off" when the input is off/. -- --
--   >>> let a1 = during (sumFrom 0) . onFor 2 . pure 1
--   
--   >>> take 5 . streamAuto' a1 $ repeat ()
--   [Just 1, Just 2, Nothing, Nothing, Nothing]
--   
-- --
--   >>> let a2 = during (sumFrom 0) . offFor 2 . pure 1
--   
--   >>> take 5 . streamAuto' a2 $ repeat ()
--   [Nothing, Nothing, Just 1, Just 2, Just 3]
--   
-- -- (Remember that pure x is the Auto that ignores -- its input and constantly just pumps out x at every step) -- -- Note the difference between putting the sumFrom "after" the -- offFor in the chain with during (like the previous -- example) and putting the sumFrom "before": -- --
--   >>> let a3 = offFor 2 . sumFrom 0 . pure 1
--   
--   >>> take 5 . streamAuto' a3 $ repeat ()
--   [Nothing, Nothing, Just 3, Just 4, Just 5]
--   
-- -- In the first case (with a2), the output of pure -- 1 was suppressed by offFor, and during -- (sumFrom 0) was only summing on the times that the 1's -- were "allowed through"...so it only "starts counting" on the third -- step. -- -- In the second case (with a3), the output of the -- pure 1 is never suppressed, and went straight into the -- sumFrom 0. sumFrom is always summing, the -- entire time. The final output of that sumFrom 0 is -- suppressed at the end with offFor 2. during :: Monad m => Auto m a b -> Interval m (Maybe a) b -- | The output stream is alwayas off, regardless of the input. -- -- Note that any monadic effects of the input Auto when composed -- with off are still executed, even though their result value is -- suppressed. -- --
--   off == pure Nothing
--   
off :: Interval m a b -- | The output stream is always on, with exactly the value of the -- corresponding input. -- --
--   toOn == arr Just
--   
toOn :: Interval m a a -- | An "interval collapsing" Auto. A stream of on/off values comes -- in; the output is the value of the input when the input is on, and the -- "default value" when the input is off. -- -- Much like fromMaybe from Data.Maybe. -- --
--   fromInterval d = arr (fromMaybe d)
--   
fromInterval :: a -> Auto m (Maybe a) a -- | Run an Auto' "interactively". Every step grab a string from -- stdin, and feed it to the Interval'. If the Interval' is -- "off", ends the session; if it is "on", then prints the output value -- to stdout and repeat all over again. -- -- If your Auto outputs something other than a String, you -- can use fmap to transform the output into a String -- en-route (like fmap show). -- -- If your Auto takes in something other than a String, you -- can lmap a function to convert the input String to -- whatever intput your Auto expects. -- -- You can use duringRead or bindRead if you have an -- Auto' or Interval' that takes something readable, -- to chug along until you find something non-readable; there's also -- interactRS which handles most of that for you. -- -- Outputs the final Interval' when the interaction terminates. interactAuto :: Interval' String String -> IO (Interval' String String) -- | Like interact, but instead of taking Interval' -- String String, takes any Interval' a -- b as long as a is Read and b is -- Show. -- -- Will "stop" if either (1) the input is not read-able or (2) the -- Interval' turns off. -- -- Outputs the final Auto' when the interaction terminates. interactRS :: (Read a, Show b) => Interval' a b -> IO (Interval' String String) -- | Turns an Auto m' a b with a list of inputs into a "ListT -- compatible effectful stream", as described at -- http://www.haskellforall.com/2014/11/how-to-build-library-agnostic-streaming.html -- -- Any library that offers a "ListT" type can use this -- result...and usually turn it into an effectful stream. -- -- For example, the pipes library offers runListT so you -- can run this, running the Auto over the input list, all with -- the effect stream manipulation tools and resource handling of -- pipes. -- -- This is useful because auto, the library, mainly provides tools -- for working with transformers for value streams, and not effect -- streams or streams of effects. Using this, you can potentially have -- the best of both worlds. streamAutoEffects :: (Monad m, MonadTrans t, MonadPlus (t m), Monad m') => (forall c. m' c -> m c) -> [a] -> Auto m' a b -> t m b -- | Turns an Auto m' a b and an "input producer" m a -- into a "ListT compatible effectful stream", as described at -- http://www.haskellforall.com/2014/11/how-to-build-library-agnostic-streaming.html -- -- Any library that offers a "ListT" type can use this -- result...and usually turn it into an effectful stream. -- -- For example, the pipes library offers runListT so you -- can run this, constantly pulling out as from the stream using -- the m a, feeding it in, and moving forward, all with the -- effect stream manipulation tools and resource handling of -- pipes. -- -- This is useful because auto, the library, mainly provides tools -- for working with transformers for value streams, and not effect -- streams or streams of effects. Using this, you can potentially have -- the best of both worlds. toEffectStream :: (Monad m, MonadTrans t, MonadPlus (t m), Monad m') => (forall c. m' c -> m c) -> m a -> Auto m' a b -> t m b