## 13 Fudget plumbing

We have already seen examples of how to use the fudget plumbing combinators. There are three basic forms of compositions: serial composition, parallel composition and loops.

```-- Serial composition:
`>==<` :: F b c -> F a b -> F a c

-- Parallel composition:
`>+<` :: F i1 o1 -> F i2 o2 -> F (Either i1 i2) (Either o1 o2)
`>*<` :: F i o -> F i o -> F i o
`listF` :: (Eq t) => [(t, F i o)] -> F (t, i) (t, o)

-- Loops:
`loopF` :: F a a -> F a a
`loopLeftF` :: F (Either loop input) (Either loop output) -> F input output
`loopThroughRightF` :: F (Either oldo newi) (Either oldi newo) ->
F oldi oldo ->
F newi newo```
The different fudget combinators treat the high-level streams in different ways, while the low-level streams are treated in the same way in all combinators. FigureĀ22 illustrates serial and parallel composition of fudgets. Figure 22. Serial and parallel composition of fudgets.

Apart from the plumbing combinators listed above, the Fudget library contains further combinators that capture common patterns. Some of these combinators are described in the following sections.

The fudget combinators have corresponding combinators for plain stream processors, which are discussed in more detail in ChapterĀ17. Their names are obtained by replacing the `F` suffix with an `SP`, or substituting `-...-` for `>...<` in the operators.

### 13.1 Serial compositions

Serial composition connects the output of one fudget to the input of another fudget. As with function composition, data flow from right to left, so that in the composition ```fud2 >==< fud1```, the output of fud1 is connected to the input of fud2.

Many of the examples in ChapterĀ9 contain serial compositions of the form

```mapF f >==< fud
fud >==< mapF f```
The library provides the following combinators to capture these cases:

```>=^< :: F a b -> (c -> a) -> F c b
fud >=^< f = fud >==< mapF f

>^=< :: (a -> b) -> F c a -> F c b
f >^=< fud = mapF f >==< fud
```
(The library versions of `>^=<` and `>=^<` have more involved definitions to be more efficient.)

Compositions of the form

```absF sp >==< fud
fud >==< absF sp```
are also common. The library provides two operators for these special cases:

```>^^=< :: SP b c -> F a b -> F a c
sp >^^=< fud = absF sp >==< fud

>=^^< :: F b c -> SP a b -> F a c
fud >=^^< sp = fud >==< absF sp```
Some combinators, like `popupMenuF` (see SectionĀ10.4), create parallel compositions of fudgets, but sometimes a serial composition is instead required. This could be accomplished by using a loop and an abstract fudget to do the necessary routing, but the library contains two combinators that do this:

```serCompLeftToRightF :: F (Either a b) (Either b c) -> F a c
serCompRightToLeftF :: F (Either a b) (Either c a) -> F b c
```
The following equations hold:
`serCompRightToLeftF (l >+< r)` = `l >==< r`
`serCompLeftToRightF (l >+< r)` = `r >==< l`

### 13.2 Parallel compositions

When combining more than two or three fudgets, the tagging obtained by using `>+<` can become a bit clumsy. It may then be more convenient to use `listF`,

`listF :: (Eq a) => [(a, F b c)] -> F (a, b) (a, c)`
which allows any type in the `Eq` class to be used as addresses of the fudgets to be combined. The restriction is that the fudgets combined must have the same type. (See SectionĀ40.4 for a discussion of how a language with dependent types could eliminate this kind of restriction.)

There is also a combinator for untagged parallel composition:

``>*<` :: F i o -> F i o -> F i o`
Input to an untagged parallel composition is sent to both argument fudgets.

There is a list version of untagged parallel composition as well,

`untaggedListF :: [F a b] -> F a b`
which can easily be defined using `>*<`:

`untaggedListF = foldr (>*<) nullF`
where `nullF`,

`nullF :: F a b`
is the fudget that ignores all input and never produces any output.

The untagged parallel compositions are not as widely used as the tagged ones. The reason is probably that you usually do not want input to be broadcast to all fudgets in a composition.

There are some further combinators that tend to be useful every once in a while. These are various parallel compositions with the identity fudget:

```idRightF :: F a b -> F (Either a c) (Either b c)
idLeftF :: F a b -> F (Either c a) (Either c b)
bypassF :: F a a -> F a a
throughF :: F a b -> F a (Either b a)

idRightF  fud = fud >+< idF
idLeftF   fud = idF >+< fud
bypassF   fud = idF >*< fud
throughF  fud = idRightF fud >==< toBothF

toBothF :: F a (Either a a)
toBothF = concatMapF (\ x -> [Left x,Right x])

idF :: F a a
idF = mapF id
```

### 13.3 Loops

The simplest loop combinator is `loopF`,

`loopF :: F a a -> F a a`
In the composition `loopF fud`, the output from fud is not only output from the composition, but also sent back to the input of fud.

The most useful loop combinator is probably `loopThroughRightF`. An example use was shown in SectionĀ9.7 and it is discussed further in SectionĀ18.2.

Some loop combinators that have been useful are:

```loopCompThroughRightF :: F (Either (Either a b) c)
(Either (Either c d) a) -> F b d

loopCompThroughLeftF :: F (Either a (Either b c))
(Either b (Either a d)) -> F c d
```
These turn parallel compositions into loops. The following equations hold:
`loopCompThroughRightF (l >+< r)` = `loopThroughRightF l r`
`loopCompThroughLeftF (l >+< r)` = `loopThroughRightF r l`

### 13.4 Dynamic fudget creation

The combinators described in the previous sections can be used to build static networks of fudgets. The Fudget library also provides combinators that can be used to add or remove fudgets dynamically (for example, to create new windows dynamically).

To create dynamically changing parallel compositions of fudgets, the library provides

`dynListF :: F (Int, DynFMsg a b) (Int, b)`
where
`data DynFMsg i o = DynCreate (F i o) | DynDestroy | DynMsg i`
Above we saw `listF` that creates tagged parallel compositions that are static. The combinator `dynListF` can be seen as a variant of `listF` with a more elaborate input message type. When the program starts, `dynListF` is an empty parallel composition. A new fudget fud with address i can be added to the parallel composition by passing the message
`(i,DynCreate fud)`
to `dynListF`. The fudget with address i can be removed from the parallel composition by passing the message
`(i,DynDestroy)`
Finally, one can send a message x to an existing fudget with address i by passing the message
`(i,DynMsg x)`
to `dynListF`.

(The addresses used by `dynListF` have been restricted to the type `Int` for efficiency reasons, but in principle, more general address types could be supported, as for ` listF`.)

A simpler combinator that allows fudgets to change dynamically is `dynF`:

`dynF :: F a b -> F (Either (F a b) a) b`
The fudget `dynF fud` starts out behaving like fud, except that messages to fud should be tagged with ` Right`. The fudget fud can be replaced by another fudget fud' by passing in the message `Left fud'`.