Skip to content

Commit

Permalink
v0.2.0.5: Added combinators and sealers for working with an underylin…
Browse files Browse the repository at this point in the history
…g `Rand` or `RandT` monad. Added *MonadRandom* as a dependency.
  • Loading branch information
mstksg committed Mar 22, 2015
2 parents a43b9aa + 3195ad4 commit b1e1982
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 94 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
0.2.0.5
-------
<https://github.com/mstksg/auto/releases/tag/v0.2.0.5>

* **Control.Auto.Process.Random**: Added combinators and sealers dealing
for working with an underlying `Rand` or `RandT` monad.
* Because of this, committed to adding `MonadRandom` as a dependency.

0.2.0.4
-------
<https://github.com/mstksg/auto/releases/tag/v0.2.0.4>
Expand Down
8 changes: 5 additions & 3 deletions auto.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: auto
version: 0.2.0.4
version: 0.2.0.5
synopsis: Denotative, locally stateful programming DSL & platform
description: (Up to date documentation is maintained at
<https://mstksg.github.com/auto>)
Expand Down Expand Up @@ -34,8 +34,9 @@ description: (Up to date documentation is maintained at
repository on github for plenty of real-world and toy
examples to learn from!
.
Support available on freenode's #haskell, and also on
the github's issue tracker.
Support available on freenode's #haskell-auto,
#haskell-game, and also on the github issue
tracker for the source repository.
.
Import "Control.Auto" to begin!

Expand Down Expand Up @@ -84,6 +85,7 @@ library
, random >= 1.1 && < 2.0
, semigroups >= 0.16.2.2 && < 0.17
, transformers >= 0.4.2.0 && < 0.5
, MonadRandom >= 0.3.0.1 && < 0.4
hs-source-dirs: src
default-language: Haskell2010
ghc-options: -Wall
12 changes: 8 additions & 4 deletions src/Control/Auto/Collection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,10 @@ dynZipF f x0 = go []
-- 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
=> (k -> Interval m a b) -- ^ function to generate a new
-- 'Interval' for each coming @k@
-- in the blip stream.
-> a -- ^ "default" input to feed in
-> Auto m ([a], Blip [k]) [b]
dynZipF_ f x0 = go []
where
Expand Down Expand Up @@ -433,8 +435,10 @@ dynMapF f x0 = go 0 IM.empty IM.empty
-- 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
=> (k -> Interval m a b) -- ^ function to generate a new
-- 'Interval' for each coming @k@
-- in the blip stream.
-> a -- ^ "default" input to feed in
-> Auto m (IntMap a, Blip [k]) (IntMap b)
dynMapF_ f x0 = go 0 IM.empty IM.empty
where
Expand Down
46 changes: 27 additions & 19 deletions src/Control/Auto/Effects.hs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,9 @@ execB mx = perBlip (arrM $ \x -> mx >> return x)
-- @foo@ be written using 'State', and being able to use it in a program
-- with no global state?
--
-- Using 'sealState'!
-- 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
Expand All @@ -263,13 +265,9 @@ execB mx = perBlip (arrM $ \x -> mx >> return x)
-- stream is the result of running the stream through @f@, first with an
-- initial state of @s0@, and afterwards with each next updated state.
--
-- This can be extended to sealing 'RandT' from the /MonadRandom/ package
-- as well, as long as you 'hoistA' first with @'StateT' . 'runRandT'@.
--
--
sealState :: (Monad m, Serialize s)
=> Auto (StateT s m) a b
-> s
=> Auto (StateT s m) a b -- ^ 'Auto' run over 'State'
-> s -- ^ initial state
-> Auto m a b
sealState a s0 = mkAutoM (sealState <$> resumeAuto a <*> get)
(saveAuto a *> put s0)
Expand All @@ -279,37 +277,37 @@ sealState a s0 = mkAutoM (sealState <$> resumeAuto a <*> get)

-- | The non-resuming/non-serializing version of 'sealState'.
sealState_ :: Monad m
=> Auto (StateT s m) a b
-> s
=> Auto (StateT s m) a b -- ^ 'Auto' run over 'State'
-> s -- ^ initial state
-> Auto m a b
sealState_ a s0 = mkAutoM (sealState_ <$> resumeAuto a <*> pure s0)
(saveAuto a)
$ \x -> do
((y, a'), s1) <- runStateT (stepAuto a x) s0
return (y, sealState_ a' s1)

-- | Turns an @a -> 'StateT' s m b@ arrow into an @'Auto' m a b@, when
-- given an initial state. Will continually "run the function", using the
-- state returned from the last run.
-- | Turns an @a -> 'StateT' s m b@ Kleisli arrow into an @'Auto' m a b@,
-- when given an initial state. Will continually "run the function", using
-- the state returned from the last run.
fromState :: (Serialize s, Monad m)
=> (a -> StateT s m b)
-> s
=> (a -> StateT s m b) -- ^ 'State' arrow
-> s -- ^ initial state
-> Auto m a b
fromState st = mkStateM (runStateT . st)

-- | Non-seralizing/non-resuming version of 'fromState'. The state isn't
-- serialized/resumed, so every time the 'Auto' is resumed, it starts over
-- with the given initial state.
fromState_ :: Monad m
=> (a -> StateT s m b)
-> s
=> (a -> StateT s m b) -- ^ 'State' arrow
-> s -- ^ initial state
-> Auto m a b
fromState_ st = mkStateM_ (runStateT . st)

-- | "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 accumulated log of the
-- underlying 'Writer' at every step.
-- output a stream @(b, w)@, where @w@ is the "new log" of the underlying
-- 'Writer' at every step.
--
-- @
-- foo :: Auto (Writer (Sum Int)) Int Int
Expand All @@ -328,7 +326,17 @@ fromState_ st = mkStateM_ (runStateT . st)
-- a list of outputs and a "final accumulator state" of 10, for stepping it
-- ten times.
--
-- We can write and compose own 'Auto's under 'Writer', using the
-- 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 'Auto's under 'Writer', using the
-- convenience of a shared accumulator, and then "use them" with other
-- 'Auto's:
--
Expand Down
Loading

0 comments on commit b1e1982

Please sign in to comment.