Fudgets are composed in the same way as plain stream processors. Therefore, the description of the stream-processor combinators also holds true for the corresponding fudget combinators. The fudget combinators are presented by name, together with some further combinators, in Chapter 13.
allows sp1 to receive input from both sp2 and sp3. For most practical purposes, sp1 can be regarded as having two input streams, as illustrated in Figure 33. When you usesp1 -==- (sp2 -+- sp3)
getSPin sp1 to read from the input streams, messages from sp2 and sp3 will appear tagged with
Right, respectively. You can not directly read selectively from one of the two input streams, but the Fudget library provides the combinator
Figure 33. Handling multiple input streams.
which you can use to wait for a selected input. Other input is queued and can be consumed after the selected input has been received. UsingwaitForSP :: (i -> Maybe i') -> (i' -> SP i o) -> SP i o
waitForSPyou can define combinators to read from one of two input streams:
getLeftSP :: (i1 -> SP (Either i1 i2) o) -> SP (Either i1 i2) o getLeftSP = waitForSP stripLeft getRightSP :: (i2 -> SP (Either i1 i2) o) -> SP (Either i1 i2) o getRightSP = waitForSP stripRight
startupSP :: [i] -> SP i o -> SP i othat prepends some elements to the input stream of a stream processor.
Note: this implementation leaves a serial composition withstartupSP xs sp = sp -==- putListSP xs idSP
idSPbehind after the messages
xshave been fed to
sp. An efficient implementation that does not leave any overhead behind can be obtained by making use of the actual representation of stream processors.
waitForSP :: (i -> Maybe i') -> (i' -> SP i o) -> SP i o waitForSP expected isp = let contSP pending = getSP $ \ msg -> case expected msg of Just answer -> startupSP (reverse pending) (isp answer) Nothing -> contSP (msg : pending) in contSP 
A variation of the loop combinators that has turned out to
be very useful when reusing stream processors is
loopThroughRightSP, illustrated in Figure 34. The key
loopLeftSP is that
the loop does not go directly back from the output to the
input of a single stream processor. Instead it goes through
another stream processor.
Figure 34. Encapsulation.
A typical situation where
loopThroughRightSP is useful
is when you have a stream processor, spold, that does
almost what you want it to do, but you need it to handle some
new kind of messages. A new stream processor, spnew, can
then be defined. This new stream processor can pass on old
messages directly to spold and handle the new messages in
the appropriate way; on its own, or by translating them to
messages that spold understands. (See also Section 3.1.1 in
In the composition
loopThroughRightSP spnew spold, all
communication with the outside world is handled by
spnew. spold is connected only to spnew, and is in this sense
encapsulated inside spnew.
The type of
Programming withloopThroughRightSP :: SP (Either oldo newi) (Either oldi newo) -> SP oldi oldo -> SP newi newo
loopThroughRightSPcorresponds to inheritance in object-oriented programming. The encapsulated stream processor corresponds to the inherited class. Overridden methods correspond to message constructors that the encapsulating stream processor handles itself.
loopLeftSPtogether with parallel and serial compositions as appropriate.
loopThroughRightSP :: SP (Either oldo i) (Either oldi o) -> SP oldi oldo ->SP i o loopThroughRightSP spnew spold = loopLeftSP (mapSP post -==- (spold -+- spnew) -==- mapSP pre) where pre (Right input) = Right (Right input) pre (Left (Left newToOld)) = Left newToOld pre (Left (Right oldToNew)) = Right (Left oldToNew) post (Right (Right output)) = Right output post (Right (Left newToOld)) = Left (Left newToOld) post (Left oldToNew) = Left (Right oldToNew)
(-==-) :: SP b c -> SP a b -> SP a c sp1 -==- sp2 = loopThroughRightSP (mapSP route) (sp1 -+- sp2) where route (Right a) = Left (Right a) route (Left (Left c)) = Right c route (Left (Right b)) = Left (Left b)
is a symmetric version ofloopThroughBothSP :: SP (Either l12 i1) (Either l21 o1) -> SP (Either l21 i2) (Either l12 o2) -> SP (Either i1 i2) (Either o1 o2)
loopThroughRightSP. A composition
loopThroughBothSP sp1 sp2allows both sp1 and sp2 to communicate with the outside world and with each other (see Figure 35).
Figure 35. Circuit diagram for
An interesting property of
that the circuit diagrams of the more basic combinators,
loopSP, can be
obtained from the circuit diagram of
by just removing wires. Other combinators are thus easy to
define in terms of
getSP) and the operators that are used to build static networks of stream processors (
loopSP, etc.). But there is in fact no reason why networks must be static. By using combinators like
-*-in a dynamic way, the number of stream processors can be made to increase dynamically. The number of stream processors can also decrease, for example if a component of a parallel composition dies (since
nullSP -*- spis equivalent to
A practical application of these ideas is discussed in Section 35.4.