The lower level one is given by the several `StateMachine` constructors, which have already been described in [How to create a machine](how-to-create-a-machine.md). They provide the most complete set of operations to compose state machines. On the other hand, some of them are quite ad-hoc and possibly temporary.
The other two live at a higher level and are provided by the `Category`/`Profunctor` hierarchy and the `Arrow` hierarchy. Let's look at them in more detail.
The `Category` type class provides us a notion of composition.
Concretely, for a type `p` with an instance of `Category`, it consists of:
- for every type `a`, an identity value `id` of type `p a a`.
- a function `(.) :: p b c -> p a b -> p a c` which allows composing values with aligning types. It needs to be associative and `id` should act as an identity both on the left and on the right.
In the context of `StateMachine`s, the `id` state machine is just the machine with a single state which emits every input it receives.
The `(.)` function is implemented as sequential composition. First a machine is executed, and every output is feed as input to the second machine.
The `Arrow p` class describes computations similarly to what `(Category p, Strong p)` do. The main difference is that is also requires that every function `a -> b` could be interpreted as `p a b`, while `p` does not need to be a `Profunctor`.
Other interesting combinators, analogous to `splitStrong` and `fanOut` are
```haskell
(***) :: p a b -> p c d -> p (a, c) (b, d)
(&&&) :: p a b -> p a c -> p a (b, c)
```
When using the `Arrow` abstraction it is also possible to use the special [`proc` notation](https://www.haskell.org/arrows/syntax.html), which allows to use a syntax similar to the one introduced by `do` notation for monads.