-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Arrowized functional state machines -- -- Arrowized functional state machines. This module is inspired by Yampa -- and the paper Functional Reactive Programming, Continued* -- written by Henrik Nilsson, Antony Courtney and John Peterson. @package AFSM @version 0.1.3.1 module Data.SF.CoreType data SF a b SF :: (a -> (SF a b, b)) -> SF a b module Data.SF.Core instance Control.Category.Category Data.SF.CoreType.SF instance Control.Arrow.Arrow Data.SF.CoreType.SF instance Control.Arrow.ArrowChoice Data.SF.CoreType.SF instance Control.Arrow.ArrowApply Data.SF.CoreType.SF instance Control.Arrow.ArrowLoop Data.SF.CoreType.SF -- | Stateful functions It is the same with SMH, and it just removes the -- empty storage. module Data.SF data SF a b SF :: (a -> (SF a b, b)) -> SF a b module Control.AFSM.CoreType -- | TF is a type representing a transition function. s: storage, a: -- input, b: output Let's explain more about TF. When a state gets -- an input a, it should do three things base on the storage and input: -- find the next state, update storage and output b. That's why it looks -- like this: (storage -> a -> (SM newState newStorage, b)) type TF -- storage input output = (storage -> input -> (SM storage input -- output, output)) Also, it is an instance of Arrow, it represents a -- machine without initial storage. composing two TF represents that two -- SM shares the same storage newtype TF s a b TF :: (s -> a -> (SM s a b, b)) -> TF s a b -- | STF is the type of simple transition function. type STF s a b = s -> a -> (s, b) -- | SM is a type representing a state machine. (TF s a b): initial -- state(transition function), s: initial storage SM storage input output -- = SM (TF storage input output) storage data SM s a b SM :: (TF s a b) -> s -> SM s a b tf :: SM s a b -> (s -> a -> (SM s a b, b)) st :: SM s a b -> s -- | It is the same with the SM constructor. newSM :: (s -> a -> (SM s a b, b)) -> s -> SM s a b -- | build a simple SM which have only one TF. simpleSM :: (s -> a -> (s, b)) -> s -> SM s a b -- | SMH is the type of the state machine with hidden or no storage. -- It is the same type with Circuit a b = Circuit (a -> Circuit a b, -- b) type SMH a b = SM () a b -- | Event type, there are 4 different events: event a, no event, -- error event string and exit event. data Event a Event :: a -> Event a NoEvent :: Event a ErrEvent :: String -> Event a ExitEvent :: Event a instance GHC.Classes.Ord a => GHC.Classes.Ord (Control.AFSM.CoreType.Event a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Control.AFSM.CoreType.Event a) instance GHC.Show.Show a => GHC.Show.Show (Control.AFSM.CoreType.Event a) instance GHC.Show.Show s => GHC.Show.Show (Control.AFSM.CoreType.SM s a b) module Control.AFSM.Util f1template :: (a1 -> a0) -> (a1 -> b0 -> b1) -> (s -> a0 -> (SM s a0 b0, b0)) -> s -> a1 -> (SM s a1 b1, b1) f2template :: (a2 -> (a0, a1)) -> (a2 -> b0 -> b1 -> b2) -> (s0 -> a0 -> (SM s0 a0 b0, b0)) -> (s1 -> a1 -> (SM s1 a1 b1, b1)) -> (s0, s1) -> a2 -> (SM (s0, s1) a2 b2, b2) absorb :: (a1 -> a0) -> (a1 -> b0 -> b1) -> SM s a0 b0 -> SM s a1 b1 merge :: (a2 -> (a0, a1)) -> (a2 -> b0 -> b1 -> b2) -> SM s0 a0 b0 -> SM s1 a1 b1 -> SM (s0, s1) a2 b2 module Control.AFSM.Core -- | Source There are two kinds of source. First one is using the output of -- `SM s a a` as its input, then it becomes a perpetual motion, :) Second -- one is a SM which ignore its input, and output something based on its -- storage. The second one is easier to understand and use. -- -- build a source, for example: buildSrc $ foldlDelaySM (const (+1)) 0 -- [0..] buildSrc $ foldlDelaySM (+) 1 [1, 2, 4, 8, ...] buildSrc :: SM s a a -> [a] -- | build a simple source, which ignore the inputs fibsSM :: SM (Int, Int) -- () Int fibsSM = simpleSM ((a, b) () -> ((b, a+b), a)) (0, 1) take -- 10 $ simpleSrc fibsSM [0,1,1,2,3, ...]simpleSrc :: SM s () a -> [a] simpleSrc :: SM s () a -> [a] -- | build a SM which just output its input idSM :: SM () a a -- | build a SM which always return b constSM :: b -> SM () a b -- | delay the input with given value. delaySM = foldlDelaySM (const id) delaySM :: a -> SM a a a -- | build a SM from a function arrSM :: (a -> b) -> SM () a b -- | the same with foldl foldlSM :: (s -> a -> s) -> s -> SM s a s -- | the difference from foldlSM is it output the storage first. foldlDelaySM :: (s -> a -> s) -> s -> SM s a s -- | absorb a function. absorbR sm f = absorbRSM sm (arrSM f) absorbL f sm -- = absorbLSM (arrSM f) sm absorbR :: SM s a b -> (b -> c) -> SM s a c absorbL :: (a -> b) -> SM s b c -> SM s a c (^>>>) :: (a -> b) -> SM s b c -> SM s a c infixr 1 ^>>> (>>>^) :: SM s a b -> (b -> c) -> SM s a c infixr 1 >>>^ (<<<^) :: SM s b c -> (a -> b) -> SM s a c infixr 1 <<<^ (^<<<) :: (b -> c) -> SM s a b -> SM s a c infixr 1 ^<<< -- | compose two SM and merge their storage. composeSM :: SM s1 b c -> SM s0 a b -> SM (s0, s1) a c -- | Right-to-left composition (<<<<) :: SM s1 b c -> SM s0 a b -> SM (s0, s1) a c infixr 1 <<<< -- | Left-to-right composition (>>>>) :: SM s0 a b -> SM s1 b c -> SM (s0, s1) a c infixr 1 >>>> firstSM :: SM s a b -> SM s (a, c) (b, c) secondSM :: SM s a b -> SM s (c, a) (c, b) productSM :: SM s0 a b -> SM s1 c d -> SM (s0, s1) (a, c) (b, d) fanoutSM :: SM s0 a b -> SM s1 a c -> SM (s0, s1) a (b, c) (****) :: SM s0 a b -> SM s1 c d -> SM (s0, s1) (a, c) (b, d) infixr 3 **** (&&&&) :: SM s0 a b -> SM s1 a c -> SM (s0, s1) a (b, c) infixr 3 &&&& leftSM :: SM s a b -> SM s (Either a c) (Either b c) rightSM :: SM s a b -> SM s (Either c a) (Either c b) sumSM :: SM s0 a b -> SM s1 c d -> SM (s0, s1) (Either a c) (Either b d) faninSM :: SM s0 a c -> SM s1 b c -> SM (s0, s1) (Either a b) c (++++) :: SM s0 a b -> SM s1 c d -> SM (s0, s1) (Either a c) (Either b d) infixr 2 ++++ (||||) :: SM s0 a c -> SM s1 b c -> SM (s0, s1) (Either a b) c infixr 2 |||| loopSM :: SM s (a, c) (b, c) -> SM s a b -- | converts SM a b -> SM [a] [b], it is very useful to compose SM a -- [b] and SM b c to SM a [c]. execSM :: SM s a b -> SM s [a] [b] joinSM :: Monad m => SM s a (m (m b)) -> SM s a (m b) concatSM :: SM s a [[b]] -> SM s a [b] -- | run SM a b with a. step :: SM s a b -> a -> (SM s a b, b) -- | execute SM a b with input [a]. Also, it is the map function for SM, -- perhaps, We should define our own Functor class, the SMFunctor! exec :: SM s a b -> [a] -> (SM s a b, [b]) -- | fmapSM f sm = sm >>> arr f fmapSM :: (b -> c) -> SM s a b -> SM s a c instance GHC.Base.Functor (Control.AFSM.CoreType.SM s a) module Control.AFSM.TF -- | transform `SM t (s, a) (s, b)` to `TF s a b` transSM2TF :: SM t (s, a) (s, b) -> TF s a b idTF :: TF s a a composeTF :: TF s b c -> TF s a b -> TF s a c arrTF :: (a -> b) -> TF s a b firstTF :: TF s a b -> TF s (a, c) (b, c) leftTF :: TF s a b -> TF s (Either a c) (Either b c) rightTF :: TF s a b -> TF s (Either c a) (Either c b) sumTF :: TF s a b -> TF s c d -> TF s (Either a c) (Either b d) faninTF :: TF s a c -> TF s b c -> TF s (Either a b) c appTF :: TF s (TF s a b, a) b loopTF :: TF s (a, c) (b, c) -> TF s a b instance Control.Category.Category (Control.AFSM.CoreType.TF s) instance Control.Arrow.Arrow (Control.AFSM.CoreType.TF s) instance Control.Arrow.ArrowChoice (Control.AFSM.CoreType.TF s) instance Control.Arrow.ArrowApply (Control.AFSM.CoreType.TF s) instance Control.Arrow.ArrowLoop (Control.AFSM.CoreType.TF s) module Control.AFSM.SMFunctor class SMFunctor f where smfmap sm a = snd $ smexec sm a smexec :: SMFunctor f => SM s a b -> f a -> (SM s a b, f b) smfmap :: SMFunctor f => SM s a b -> f a -> f b smexecSM :: SMFunctor f => SM s a b -> SM s (f a) (f b) smexecSMA :: SMFunctor f => SM s a b -> SM (SM s a b) (f a) (f b) bindSM :: (Monad m, SMFunctor m) => m a -> SM s a (m b) -> (SM s a (m b), m b) (>>>=) :: (Monad m, SMFunctor m) => m a -> SM s a (m b) -> m b instance Control.AFSM.SMFunctor.SMFunctor [] instance Control.AFSM.SMFunctor.SMFunctor GHC.Base.Maybe instance Control.AFSM.SMFunctor.SMFunctor ((->) r) instance Control.AFSM.SMFunctor.SMFunctor (Data.Either.Either a) instance Control.AFSM.SMFunctor.SMFunctor ((,) a) instance (Control.AFSM.SMFunctor.SMFunctor f, Control.AFSM.SMFunctor.SMFunctor g) => Control.AFSM.SMFunctor.SMFunctor (Data.Functor.Compose.Compose f g) module Control.AFSM.Event -- | Event type, there are 4 different events: event a, no event, -- error event string and exit event. data Event a = Event a | NoEvent | -- ErrEvent String | ExitEvent deriving (Show, Eq, Ord) -- -- extract [a] from [Event a] extractEvents :: [Event a] -> [a] instance GHC.Base.Functor Control.AFSM.CoreType.Event instance GHC.Base.Applicative Control.AFSM.CoreType.Event instance GHC.Base.Monad Control.AFSM.CoreType.Event instance Control.AFSM.SMFunctor.SMFunctor Control.AFSM.CoreType.Event module Control.AFSM.SMH -- | the same constructor with newSM newSMH :: (() -> a -> (SMH a b, b)) -> SMH a b -- | the same constructor with simpleSM simpleSMH :: (s -> a -> (s, b)) -> s -> SMH a b -- | hide the Storage type in the transition function. hideStorage :: SM s a b -> SMH a b instance Control.Category.Category (Control.AFSM.CoreType.SM ()) instance Control.Arrow.Arrow (Control.AFSM.CoreType.SM ()) instance Control.Arrow.ArrowChoice (Control.AFSM.CoreType.SM ()) instance Control.Arrow.ArrowApply (Control.AFSM.CoreType.SM ()) instance Control.Arrow.ArrowLoop (Control.AFSM.CoreType.SM ()) -- | Arrowized functional state machines. -- -- This module is inspired by Yampa and the paper Functional Reactive -- Programming, Continued* written by Henrik Nilsson, Antony Courtney -- and John Peterson. module Control.AFSM -- | Event type, there are 4 different events: event a, no event, -- error event string and exit event. data Event a Event :: a -> Event a NoEvent :: Event a ErrEvent :: String -> Event a ExitEvent :: Event a class SMFunctor f where smfmap sm a = snd $ smexec sm a smexec :: SMFunctor f => SM s a b -> f a -> (SM s a b, f b) smfmap :: SMFunctor f => SM s a b -> f a -> f b -- | TF is a type representing a transition function. s: storage, a: -- input, b: output Let's explain more about TF. When a state gets -- an input a, it should do three things base on the storage and input: -- find the next state, update storage and output b. That's why it looks -- like this: (storage -> a -> (SM newState newStorage, b)) type TF -- storage input output = (storage -> input -> (SM storage input -- output, output)) Also, it is an instance of Arrow, it represents a -- machine without initial storage. composing two TF represents that two -- SM shares the same storage newtype TF s a b TF :: (s -> a -> (SM s a b, b)) -> TF s a b -- | transform `SM t (s, a) (s, b)` to `TF s a b` transSM2TF :: SM t (s, a) (s, b) -> TF s a b -- | SM is a type representing a state machine. (TF s a b): initial -- state(transition function), s: initial storage SM storage input output -- = SM (TF storage input output) storage data SM s a b SM :: (TF s a b) -> s -> SM s a b -- | It is the same with the SM constructor. newSM :: (s -> a -> (SM s a b, b)) -> s -> SM s a b -- | build a simple SM which have only one TF. simpleSM :: (s -> a -> (s, b)) -> s -> SM s a b tf :: SM s a b -> (s -> a -> (SM s a b, b)) st :: SM s a b -> s -- | SMH is the type of the state machine with hidden or no storage. -- It is the same type with Circuit a b = Circuit (a -> Circuit a b, -- b) type SMH a b = SM () a b -- | the same constructor with newSM newSMH :: (() -> a -> (SMH a b, b)) -> SMH a b -- | the same constructor with simpleSM simpleSMH :: (s -> a -> (s, b)) -> s -> SMH a b -- | hide the Storage type in the transition function. hideStorage :: SM s a b -> SMH a b -- | Source There are two kinds of source. First one is using the output of -- `SM s a a` as its input, then it becomes a perpetual motion, :) Second -- one is a SM which ignore its input, and output something based on its -- storage. The second one is easier to understand and use. -- -- build a source, for example: buildSrc $ foldlDelaySM (const (+1)) 0 -- [0..] buildSrc $ foldlDelaySM (+) 1 [1, 2, 4, 8, ...] buildSrc :: SM s a a -> [a] -- | build a simple source, which ignore the inputs fibsSM :: SM (Int, Int) -- () Int fibsSM = simpleSM ((a, b) () -> ((b, a+b), a)) (0, 1) take -- 10 $ simpleSrc fibsSM [0,1,1,2,3, ...]simpleSrc :: SM s () a -> [a] simpleSrc :: SM s () a -> [a] -- | build a SM which always return b constSM :: b -> SM () a b -- | build a SM which just output its input idSM :: SM () a a -- | delay the input with given value. delaySM = foldlDelaySM (const id) delaySM :: a -> SM a a a -- | build a SM from a function arrSM :: (a -> b) -> SM () a b -- | the same with foldl foldlSM :: (s -> a -> s) -> s -> SM s a s -- | the difference from foldlSM is it output the storage first. foldlDelaySM :: (s -> a -> s) -> s -> SM s a s -- | compose two SM and merge their storage. composeSM :: SM s1 b c -> SM s0 a b -> SM (s0, s1) a c -- | Left-to-right composition (>>>>) :: SM s0 a b -> SM s1 b c -> SM (s0, s1) a c infixr 1 >>>> -- | Right-to-left composition (<<<<) :: SM s1 b c -> SM s0 a b -> SM (s0, s1) a c infixr 1 <<<< (^>>>) :: (a -> b) -> SM s b c -> SM s a c infixr 1 ^>>> (>>>^) :: SM s a b -> (b -> c) -> SM s a c infixr 1 >>>^ (^<<<) :: (b -> c) -> SM s a b -> SM s a c infixr 1 ^<<< (<<<^) :: SM s b c -> (a -> b) -> SM s a c infixr 1 <<<^ firstSM :: SM s a b -> SM s (a, c) (b, c) secondSM :: SM s a b -> SM s (c, a) (c, b) (****) :: SM s0 a b -> SM s1 c d -> SM (s0, s1) (a, c) (b, d) infixr 3 **** (&&&&) :: SM s0 a b -> SM s1 a c -> SM (s0, s1) a (b, c) infixr 3 &&&& leftSM :: SM s a b -> SM s (Either a c) (Either b c) rightSM :: SM s a b -> SM s (Either c a) (Either c b) (++++) :: SM s0 a b -> SM s1 c d -> SM (s0, s1) (Either a c) (Either b d) infixr 2 ++++ (||||) :: SM s0 a c -> SM s1 b c -> SM (s0, s1) (Either a b) c infixr 2 |||| loopSM :: SM s (a, c) (b, c) -> SM s a b absorb :: (a1 -> a0) -> (a1 -> b0 -> b1) -> SM s a0 b0 -> SM s a1 b1 merge :: (a2 -> (a0, a1)) -> (a2 -> b0 -> b1 -> b2) -> SM s0 a0 b0 -> SM s1 a1 b1 -> SM (s0, s1) a2 b2 -- | converts SM a b -> SM [a] [b], it is very useful to compose SM a -- [b] and SM b c to SM a [c]. execSM :: SM s a b -> SM s [a] [b] concatSM :: SM s a [[b]] -> SM s a [b] -- | run SM a b with a. step :: SM s a b -> a -> (SM s a b, b) -- | execute SM a b with input [a]. Also, it is the map function for SM, -- perhaps, We should define our own Functor class, the SMFunctor! exec :: SM s a b -> [a] -> (SM s a b, [b])