I think what you are looking for a is "(pure) functional reactive programming".
The problem with caching is that it is very often highly individual and it usually comes with drawbacks, i.e. you win performance here but lose it there or you win performance but you lose consistency. (related: CAP theorem)
So I doubt there is any "generic" solution that will or even could make you happy. But if you find one, let me know. :-)
Well, in a single-threadsd environment you almost can have consistency, and you can cache the latest results. What I am saying is that if a result consists of X1, X2, X3 but you don’t need all of them for a certain request, then you wind up caching X1, X2 one time, and requesting X1, X3 another time, what to do with the cache of (X1, X2)? Currently I just update the caches which are subsets (X1) of a cached response, and do it with manual individual code. I hoped that I could have some sort of dependency graph. Maybe reactive programming, yeah. But that would essentially be some sort of declarative language, to run pure functions which still have custom code. Hmm
Single threaded just means there is no parallelization, but there can (and usually is) still concurrency, which is what reactive programming is about.
I think reactive programing solves the "dependency graph" problem to you in the sense that you just have to "change" one value and then all dependencies (and their dependencies) update. You still have to define the relations though.
The problem with caching is that it is very often highly individual and it usually comes with drawbacks, i.e. you win performance here but lose it there or you win performance but you lose consistency. (related: CAP theorem)
So I doubt there is any "generic" solution that will or even could make you happy. But if you find one, let me know. :-)