circuits
Safe HaskellNone
LanguageGHC2024

Circuit.Process

Description

A pointed Moore machine packaged as a Circuit base arrow.

data Process a b = forall s. Process (a -> s) (s -> a -> s) (s -> b)

Process is the monomial special case of System: the interface is Mono a b and the initial state is supplied by the first input. The underlying span-shaped carrier is Body.

  • inject converts the first input into an initial state.
  • step updates the state given the current input.
  • extract produces the output from the current state.

This is the circuits-native carrier for streaming state machines. It is intended to replace the hand-rolled state-machine arrow: stats packages become boxes Process a b, while the arrow itself lives in the substrate next to Trace and Net.

The semantics are intentionally tied to the circuits substrate:

  • scan is the reference runner over lists.
  • scanStream generalizes this to any Uncons input and Cons output.
  • encode maps a process into a stream-level Trace Either (->) over lists; the two runners are verified equivalent by oracle.
  • The arrow-level Traced Either instance is per-tick Conway/Elgot settle, not cross-tick state feedback; see register for the latter.

Pointed systems

The pointed-Moore view of a stateful morphism is System with an explicit seed. Use mooreSystem to build such a system, and systemToProcess to turn it into a first-input-seeded Process.

Synopsis

Stream transformer (monomial special case)

data Process a b where Source #

A stateful process from a to b.

The existential state type s is hidden; the observable interface is the triple inject step extract. Keeping the triple as the primitive (rather than fusing extract into the step) preserves the streaming-statistics invariant that the first output is extract (inject x), before any step.

Constructors

Process :: forall s a b. (a -> s) -> (s -> a -> s) -> (s -> b) -> Process a b 

Instances

Instances details
Copy (->) a => Copy Process a Source # 
Instance details

Defined in Circuit.Process

Methods

copy :: Process a (a, a) Source #

Merge (->) a => Merge Process a Source # 
Instance details

Defined in Circuit.Process

Methods

plus :: Process (a, a) a Source #

Category Process Source # 
Instance details

Defined in Circuit.Process

Methods

id :: Process a a Source #

(.) :: Process b c -> Process a b -> Process a c Source #

Shared (,) Process Source #

Cartesian shared fusion on processes.

The two processes share one feedback channel s. At each tick the schedule chooses which body advances; the gated body's input is discarded and it does not step. Each process is injected lazily on its first firing, so a body that is never scheduled consumes no inputs and produces no outputs.

Instance details

Defined in Circuit.Process

Methods

sharedBy :: Schedule s -> Process (s, a) (s, b) -> Process (s, c) (s, d) -> Process (s, (a, c)) (s, These b d) Source #

Discard Process (a :: Type) Source # 
Instance details

Defined in Circuit.Process

Methods

discard :: Process a () Source #

Zero (->) a => Zero Process (a :: Type) Source # 
Instance details

Defined in Circuit.Process

Methods

zero :: Process () a Source #

Channel Either Process Source # 
Instance details

Defined in Circuit.Process

Methods

assoc :: Process (Either (Either a b) c) (Either a (Either b c)) Source #

assoc' :: Process (Either a (Either b c)) (Either (Either a b) c) Source #

slide :: Process (Either a (Either b c)) (Either b (Either a c)) Source #

Channel (,) Process Source # 
Instance details

Defined in Circuit.Process

Methods

assoc :: Process ((a, b), c) (a, (b, c)) Source #

assoc' :: Process (a, (b, c)) ((a, b), c) Source #

slide :: Process (a, (b, c)) (b, (a, c)) Source #

Strength Either Process Source # 
Instance details

Defined in Circuit.Process

Methods

strength :: Process b c -> Process (Either a b) (Either a c) Source #

Strength (,) Process Source # 
Instance details

Defined in Circuit.Process

Methods

strength :: Process b c -> Process (a, b) (a, c) Source #

Traced Either Process Source # 
Instance details

Defined in Circuit.Process

Methods

trace :: Process (Either a b) (Either a c) -> Process b c Source #

Traced (,) Process Source # 
Instance details

Defined in Circuit.Process

Methods

trace :: Process (a, b) (a, c) -> Process b c Source #

Action (,) Process Source # 
Instance details

Defined in Circuit.Process

Methods

braid :: Process (a, b) (b, a) Source #

Tensor (,) Process Source # 
Instance details

Defined in Circuit.Process

Methods

tensor :: Process a b -> Process c d -> Process (a, c) (b, d) Source #

Unital (,) Process Source # 
Instance details

Defined in Circuit.Process

Boundary tokens (K + payload)

data Boundary k a Source #

The free boundary K + payload.

A token on the boundary is either a mark from a finite alphabet k or a payload value a. This is the level-0 grammar of process boundaries: marks are the control tokens, payloads are the data.

fmap acts only on the payload side; marks are carried through unchanged.

>>> fmap length (Payload "hi")
Payload 2
>>> fmap length (Mark "halt")
Mark "halt"

Constructors

Mark k

Control token from the finite mark alphabet.

Payload a

Data-carrying payload.

Instances

Instances details
Bifunctor Boundary Source # 
Instance details

Defined in Circuit.Process

Methods

bimap :: (a -> b) -> (c -> d) -> Boundary a c -> Boundary b d #

first :: (a -> b) -> Boundary a c -> Boundary b c #

second :: (b -> c) -> Boundary a b -> Boundary a c #

Functor (Boundary k) Source # 
Instance details

Defined in Circuit.Process

Methods

fmap :: (a -> b) -> Boundary k a -> Boundary k b #

(<$) :: a -> Boundary k b -> Boundary k a #

Foldable (Boundary k) Source # 
Instance details

Defined in Circuit.Process

Methods

fold :: Monoid m => Boundary k m -> m #

foldMap :: Monoid m => (a -> m) -> Boundary k a -> m #

foldMap' :: Monoid m => (a -> m) -> Boundary k a -> m #

foldr :: (a -> b -> b) -> b -> Boundary k a -> b #

foldr' :: (a -> b -> b) -> b -> Boundary k a -> b #

foldl :: (b -> a -> b) -> b -> Boundary k a -> b #

foldl' :: (b -> a -> b) -> b -> Boundary k a -> b #

foldr1 :: (a -> a -> a) -> Boundary k a -> a #

foldl1 :: (a -> a -> a) -> Boundary k a -> a #

toList :: Boundary k a -> [a] #

null :: Boundary k a -> Bool #

length :: Boundary k a -> Int #

elem :: Eq a => a -> Boundary k a -> Bool #

maximum :: Ord a => Boundary k a -> a #

minimum :: Ord a => Boundary k a -> a #

sum :: Num a => Boundary k a -> a #

product :: Num a => Boundary k a -> a #

Traversable (Boundary k) Source # 
Instance details

Defined in Circuit.Process

Methods

traverse :: Applicative f => (a -> f b) -> Boundary k a -> f (Boundary k b) #

sequenceA :: Applicative f => Boundary k (f a) -> f (Boundary k a) #

mapM :: Monad m => (a -> m b) -> Boundary k a -> m (Boundary k b) #

sequence :: Monad m => Boundary k (m a) -> m (Boundary k a) #

(Eq k, Eq a) => Eq (Boundary k a) Source # 
Instance details

Defined in Circuit.Process

Methods

(==) :: Boundary k a -> Boundary k a -> Bool #

(/=) :: Boundary k a -> Boundary k a -> Bool #

(Show k, Show a) => Show (Boundary k a) Source # 
Instance details

Defined in Circuit.Process

Methods

showsPrec :: Int -> Boundary k a -> ShowS #

show :: Boundary k a -> String #

showList :: [Boundary k a] -> ShowS #

isMark :: Boundary k a -> Bool Source #

True iff the token is a Mark.

isPayload :: Boundary k a -> Bool Source #

True iff the token is a Payload.

System - Process conversions

systemToProcess :: s -> (s -> b) -> System (->) s (Mono a b) -> Process a b Source #

Convert a monomial System, an explicit seed, and a state observation into a first-input-seeded Process.

The observation s -> b is applied to the current state to produce each output, including the first output from the seed. The step system is used only for state transitions.

systemAsProcess :: System (->) s (Mono i o) -> s -> Process i o Source #

Convert a monomial System into a Process machine with a given initial state.

The first input is consumed for the state transition from the supplied initial state, matching the coalgebra intuition of a System.

markSystem :: (k -> Bool) -> (s -> b) -> System (->) s (Mono a b) -> System (->) (Either s s) (Mono (Boundary k a) (Maybe b)) Source #

Lift a monomial System and a state observation into a boundary system over Boundary tokens.

Payloads are stepped through the inner system. Marks satisfying the halt predicate freeze the system and produce Nothing thereafter; non-halt marks leave the state unchanged and emit the current output. The halted state remembers the final inner state.

The returned system carries state Either s s: Left is running, Right is halted. This is the core combinator behind mark-driven halt: the finite mark alphabet k carries control tokens, while payloads carry data.

Runners

iterateSystem :: System (->) s (Mono i o) -> s -> [i] -> [o] Source #

Run a system for as many steps as there are inputs, emitting one output per input. The output is the state after consuming the input, matching the Process semantics of systemAsProcess.

after :: System (->) s (Mono i o) -> s -> [i] -> s Source #

State after consuming a list of inputs.

scan :: Process a b -> [a] -> [b] Source #

List specialization of scanStream.

scanStream :: (Uncons f a, Cons g b) => Process a b -> f -> g Source #

Run a process over any stream with an Uncons coalgebra and build the output with a Cons algebra.

The first element seeds the hidden channel via inject; each subsequent element steps it via step; each output is extract of the current channel.

fold :: Process a b -> [a] -> Maybe b Source #

List specialization of foldStream.

foldStream :: Uncons f a => Process a b -> f -> Maybe b Source #

Run a process over a stream, returning the final output (if any).

encode :: Process a b -> Trace Either (->) [a] [b] Source #

List specialization of encodeStream.

encodeStream :: (Uncons f a, Cons g b) => Process a b -> Trace Either (->) f g Source #

Encode a process as a stream-level Trace over arbitrary Uncons/Cons streams.

This is the definitional runner: scanStream is eval composed with encodeStream. The feedback channel carries (Maybe channel, remaining input, accumulated output).

Mealy-style processes

mealy :: ch -> (ch -> a -> (ch, Maybe b)) -> Process a (Maybe b) Source #

Build a Process from a Mealy-style step.

The output may depend on the current input. The channel internally stores the most recent output so that the Moore-style Process interface is preserved.

runMealy :: Process a (Maybe b) -> [a] -> [b] Source #

List specialization of runMealyStream.

runMealyStream :: (Uncons f a, Cons g b) => Process a (Maybe b) -> f -> g Source #

Collect the emitted outputs of a 'Process (Maybe b)' over any stream.

Cross-tick feedback

delay :: s -> Process s s Source #

One-tick delay with an initial value.

Output is s0 on the first tick and the input from the previous tick thereafter. This is the primitive that makes register productive: the feedback wire is observable one tick late.

register :: s -> Process (a, s) (b, s) -> Process a b Source #

Cross-tick register feedback.

Given an initial feedback value s0 and a process Process (a, s) (b, s), close the s wire so that the s produced at one tick is fed back as input at the next tick. This is the productive, strict-accumulator-safe analogue of the cartesian trace: the delay is explicit in the wiring rather than implicit in a lazy knot.

Compare with the cartesian trace on Process, which ties a lazy knot and diverges for strict state; register keeps strict state cells sound by making the one-tick delay observable.

For bodies whose fixed-point is independent of the initial feedback value (e.g. affine/stateless feedback such as ewmaBody), the same wiring can be expressed by swapping the feedback wire into the active position, applying strength (delay s0), and tracing.

Body conversions

processToBody :: Process a b -> SomeBody Either (->) [a] [b] Source #

List specialization of processToBodyStream.

processToSomeBody :: Process a b -> SomeBody (,) (->) a b Source #

View a Process as an existentially-quantified Body.

The process state is exposed as the ambient wire. The initial state is Nothing; the first input is fed to inject to create the real state, and subsequent inputs use step. The output is always extract of the current state.