But this brings up a question about concrete structures and abstract qualities of programming languages.
Looking at, say, chapter 2, you have the problem of finding the least-costly recipe for a given task mapped to the abstract monoid structure.
Now, I understand a very nice approach where you essentially go:
Concrete real-world-problem -> abstract-problem, then utilize standard-abstract-facility for solving abstract-problem. If the abstract-facility is incorporated into the language itself, this can happen "effortlessly" and nearly invisibly.
But, this happy scenario can become an unhappy scenario when you have done all that, it works well, when suddenly you find the concrete problem has qualities that are completely irregular and don't fit the abstract model at all. Suppose cost of recipes varies in some weird, ad-hoc fashion, etc.
What to do? Data behaving in a regular fashion is the font of mathematical structures and allows powerful tools. But change that regular behavior to something less regular and you may or may-not get something ammenable to further abstract manipulation.
The thing is, if you take "recipes" becoming "monoids" and have your own library for deriving a category theoretical solution, and if then what "recipes" do suddenly is less category theoretical, then you can change your library - perhaps in a way that does violence to the concepts but still happens to work. But if you take "recipes" and use the built-in language facilities for the monoidal properties of a problem, you may have a lot more trouble modifying the map between concrete problem and abstract solution. And certainly, the modified library may be a long-term terrible solution if you expect the problem to grow. But suppose you don't, suppose you can benefit from exactly this level of abstraction and ad-hoc modification and would pay a bit for a lot of abstraction.
Is there something I'm missing in this criticism?