>35 years professional software engineering, 30 years in embedded. I'm going to guess that you have less.
Doesn't change the fact that you're wrong and 35 years of programming doesn't ensure that you're a good developer. There are examples of crap code and patterns that have been around perpetually.
>Why is state data used everywhere? Because embedded systems often respond in different ways depending on the state of external inputs
State being everywhere doesn't preclude it to being segregated from logic.
>If those decisions are spread through the bulk of the code, there's really not much left to put in your combinator. And there's no point in trying to add that paradigm to a system that's going to have tons of shared mutable state anyway.
The decision is what goes in the combinator.
#IO functions.
Data getIOFromModuleA()
void sendIOToModuleA(Response r)
Data getIOFromModuleB()
void sendIOToModuleB(Response r)
....
# combinators, reuseable in both module A and module B because of segregation from IO and State
Decision makeDecision(Data x)
Response createResponse(Decision x)
It's the same pattern for State. Just replace the word IO with State. Response can be anything, it can be the entire new state of the program. It can represent a delta of a change, it can be a response specific to a module. Also again, all threading commands go into State or IO functions.
OOP fails to segregate code this way and if you don't organize your code like this then you have 35 years of experience of navigating someone elses mess or your own.