packages feed

automaton 1.3 → 1.4

raw patch · 7 files changed

+106/−6 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Automaton: unfold_ :: Applicative m => s -> (a -> s -> s) -> Automaton m a s
+ Data.Automaton.Trans.Accum: accumS :: (Functor m, Monad m) => Automaton m (w, a) (w, b) -> Automaton (AccumT w m) a b
+ Data.Automaton.Trans.Accum: runAccumS :: (Functor m, Monad m) => Automaton (AccumT w m) a b -> Automaton m (w, a) (w, b)
+ Data.Automaton.Trans.Accum: runAccumS_ :: (Functor m, Monoid w, Monad m) => Automaton (AccumT w m) a b -> Automaton m a (w, b)
+ Data.Automaton.Trans.Accum: runAccumS__ :: (Functor m, Monoid w, Monad m) => Automaton (AccumT w m) a b -> Automaton m a b

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for automaton -## 0.1.0.0+## 1.4 -* Initial version ;)+* Added `Data.Automaton.Trans.Accum`+* Added `unfold_`+* Backwards compatible to 1.3, but to keep version numbers in sync with rhine, the automaton version has also been bumped++## 1.3++* Initial version
automaton.cabal view
@@ -1,11 +1,11 @@ cabal-version: 3.0 name: automaton-version: 1.3+version: 1.4 synopsis: Effectful streams and automata in initial encoding description:   Effectful streams have an internal state and a step function.   Varying the effect type, this gives many different useful concepts:-  For example with a reader effect, it results in automata/transducers/state machines.+  For example with a reader effect, it results in automata (a.k.a transducers or state machines).  license: MIT license-file: LICENSE@@ -24,7 +24,7 @@ source-repository this   type: git   location: https://github.com/turion/rhine.git-  tag: v1.3+  tag: v1.4  common opts   build-depends:@@ -65,6 +65,7 @@   exposed-modules:     Data.Automaton     Data.Automaton.Final+    Data.Automaton.Trans.Accum     Data.Automaton.Trans.Except     Data.Automaton.Trans.Maybe     Data.Automaton.Trans.RWS@@ -93,6 +94,7 @@   other-modules:     Automaton     Automaton.Except+    Automaton.Trans.Accum     Stream    build-depends:
src/Data/Automaton.hs view
@@ -111,6 +111,16 @@   Automaton m a b unfoldM state step = Automaton $! Stateful $! StreamT {state, step = \s -> ReaderT $ \a -> step a s} +-- | Like 'unfold', but output the current state.+unfold_ ::+  (Applicative m) =>+  -- | The initial state+  s ->+  -- | The step function+  (a -> s -> s) ->+  Automaton m a s+unfold_ state step = unfold state $ \a s -> let s' = step a s in Result s' s'+ instance (Eq s, Floating s, VectorSpace v s, Applicative m) => VectorSpace (Automaton m a v) (Automaton m a s) where   zeroVector = Automaton zeroVector   Automaton s *^ Automaton v = coerce $ s *^ v
+ src/Data/Automaton/Trans/Accum.hs view
@@ -0,0 +1,60 @@+{- | Handle a global 'AccumT' layer in an 'Automaton'.++A global accumulation state can be hidden by an automaton by making it an internal state.+-}+module Data.Automaton.Trans.Accum (+  module Control.Monad.Trans.Accum,+  accumS,+  runAccumS,+  runAccumS_,+  runAccumS__,+)+where++-- base+import Control.Arrow (arr, returnA, (>>>))++-- transformers+import Control.Monad.Trans.Accum++-- automaton+import Data.Automaton (Automaton, feedback, withAutomaton)+import Data.Stream.Result (Result (..))++{- | Convert from explicit states to the 'AccumT' monad transformer.++The original automaton is interpreted to take the current accumulated state as input and return the log to be appended as output.++This is the opposite of 'runAccumS'.+-}+accumS :: (Functor m, Monad m) => Automaton m (w, a) (w, b) -> Automaton (AccumT w m) a b+accumS = withAutomaton $ \f a -> AccumT $ \w ->+  (\(Result s (w', b)) -> (Result s b, w'))+    <$> f (w, a)++{- | Make the accumulation transition in 'AccumT' explicit as 'Automaton' inputs and outputs.++This is the opposite of 'accumS'.+-}+runAccumS :: (Functor m, Monad m) => Automaton (AccumT w m) a b -> Automaton m (w, a) (w, b)+runAccumS = withAutomaton $ \f (w, a) ->+  (\(Result s b, w') -> Result s (w', b))+    <$> runAccumT (f a) w++{- | Convert global accumulation state to internal state of an 'Automaton'.++The current state is output on every step.+-}+runAccumS_ ::+  (Functor m, Monoid w, Monad m) =>+  -- | An automaton with a global accumulation state effect+  Automaton (AccumT w m) a b ->+  Automaton m a (w, b)+runAccumS_ automaton = feedback mempty $ proc (a, wState) -> do+  (wAdd, b) <- runAccumS automaton -< (wState, a)+  let wState' = wState <> wAdd+  returnA -< ((wState', b), wState')++-- | Like 'runAccumS_', but don't output the current accum.+runAccumS__ :: (Functor m, Monoid w, Monad m) => Automaton (AccumT w m) a b -> Automaton m a b+runAccumS__ automaton = runAccumS_ automaton >>> arr snd
test/Automaton.hs view
@@ -28,6 +28,7 @@  -- automaton import Automaton.Except+import Automaton.Trans.Accum import Data.Automaton import Data.Automaton.Final import Data.Automaton.Trans.Maybe@@ -70,6 +71,7 @@     , testCase "sumN" $ runIdentity (embed (arr (const (1 :: Integer)) >>> sumN) [(), (), ()]) @?= [1, 2, 3]     , testCase "lastS" $ runIdentity (embed (lastS 0) [Nothing, Just 10]) @?= [0, 10]     , Automaton.Except.tests+    , Automaton.Trans.Accum.tests     ]  inMaybe :: Automaton Maybe (Maybe a) a
test/Automaton/Except.hs view
@@ -9,7 +9,7 @@ -- tasty-hunit import Test.Tasty.HUnit (testCase, (@?=)) --- rhine+-- automaton import Data.Automaton (embed) import Data.Automaton.Trans.Except (safe, safely, step) 
+ test/Automaton/Trans/Accum.hs view
@@ -0,0 +1,20 @@+module Automaton.Trans.Accum where++-- base+import Control.Monad.Identity (Identity (runIdentity))+import Data.Monoid (Sum (..))++-- transformers+import Control.Monad.Trans.Accum (add, look)++-- tasty+import Test.Tasty (testGroup)++-- tasty-hunit+import Test.Tasty.HUnit (testCase, (@?=))++-- automaton+import Data.Automaton+import Data.Automaton.Trans.Accum (runAccumS_)++tests = testGroup "Trans.Accum" [testCase "runAccumS_" $ runIdentity (embed (runAccumS_ (constM (add (Sum 1) >> look))) (replicate 5 ())) @?= (\n -> (n, n)) <$> [1, 2, 3, 4, 5]]