Isn’t all programming “compositional”? I mean… if there was no data flow to and from other code it would be dead code. All that Haskell stuff is still a bit above me.
I think what the author means by “compositional” in this context is the idea of being able to compose (ie, stitch together) functions (or other components like that) into larger components, in such a way that certain laws hold. What those laws say are that the order you stitch those components together doesn’t matter (ie, if you have components A, B, and C that have the right types, you can put A and B together, and then add C after them, or you can put B and C together, and then add A before them, and both will yield an identical thing that we can call ABC), and that there is some sort of identity component that you can always add before or after and it won’t change things.
More concretely, what this is talking about is the idea that those components have “types” that suffice to describe them, to the point of allowing you to stitch them together. So if you have a component f and it takes as input A and produces as output B, you can always put a component that consumes B after it, and can always put something that produces A before it. This is a really powerful design idea, as it means you have to be conscious of all the things that make up the input and all the things that make up the output. Most programming doesn’t do that, and as a result, the input and output types are pretty unwieldy, which means it is harder to re-use components in different ways. When you take this as a design principle, you try to make those types crisp, and as a result, get better flexibility.
One really good example of this in action is the suite of unix utilities that all take input on standard in and write output to standard out. Because they fulfill this, and they don’t do other things as well, and don’t require other setup, or only running after a certain other command has already run, we can combine them in all sorts of ways.
There are a lot of cases where things “don’t compose”, and although this can be a subjective notion, the concept of a Category is there to make it more rigorous. Function composition is the simplest notion of composition (no side effects) and Kleisli composition is sequencing of stateful actions.
An example of non-composition: lock-based programming. P and Q can be working programs with no errors, but when running together, they can deadlock. That’s one of the reasons why we prefer solutions like STM or non-blocking asynchronous programming.