In the programming language Haskell, it is normal to work with functions that depend only on their input values, and which do nothing except return an output value. Functional programming is generally much easier to reason about, because there's no chance of one piece of a program making a change to global state that affects an apparently unrelated part of the program.
This does leave the problem of how a function program can communicate with the outside world. Various approaches have been tried, and the one Haskell chooses is particularly elegant. Functions that need to accept input or produce output take an IO object as a parameter and produce a (generally different) IO object as the result. The IO object "encapsulates" the entire world outside the program. To actually run a Haskell program, the machine performs a sequence of IO transformations - taking one IO object, evaluating the program as much as necessary to determine the next IO object, and then actually performing the corresponding input or output operation before restarting the loop.
So there's a sort of inversion between how we normally think about function evaluation and how the evaluation actually happens. One can't really pass around the entire state of the universe as a parameter the way a C programmer would pass an int, so one must fake it by moving the "state of the universe" to the outside of the program and rearranging everything else so that it works the same way as it would if you could.
I can't prove it, but I think there's a very deep idea here with implications for how we understand the universe and our place in it. Much like pure functions can't describe IO, it seems like physics as we understand it can't describe human consciousness (in particular, subjective experience). Some suggest that this means consciousness is an illusion, but this has never been a satisfying answer to me.
Physics is done by describing the universe objectively - there are these particles at these positions and such and such a field had value x over here at this time (somewhat like values in a Haskell program). There are rules describing how the state of the universe evolves through time (somewhat like pure functions). But none of these things really seem to be able to describe what it is like to "feel" seeing the colour red (for example). Physics can describe a stream of 700nm wavelength photons hitting a retina, causing neurons to fire in particular patterns, some of which resemble the patterns that have occurred when the same retina received 700nm photons previously. These patterns then provoke other patterns which previously occurred in conjunction with the "700nm" patterns, and cause the release of small amounts of hormones. Understanding this system completely (which admittedly we don't) would allow one to (in principle) predict exactly which previous experiences would be recalled by any given stimulus, and might even allow one to predict exactly how the stimulated individual would react. But none of this seems to be able to tell us what experiencing red is actually like because we have no way to describe subjective experiences objectively.
We experience the universe entirely from a subjective point of view - through our senses. The objective model is useful because it allows us to reason, communicate and simulate but I suspect that in saying that objective reality is the real thing and subjective reality is just an illusion, we would be making a mistake and not seeing the forest for the trees.
Instead, I would like to suggest that we perform the same inversion that the Haskell compiler does. Instead of thinking of human beings as unexplained (possibly unexplainable) things within an objective universe, think of them as the IO hooks of the universe: input from free will (assuming that it exists) and output to subjective experience. This IO doesn't (necessarily) go to "another universe" - it's just a primitive, axiomatic thing that may have no more relevance to our objective universe than the implementation details of the IO monad do to a pure functional Haskell program. Experiencing life is running the program.
One important difference between the universe and a Haskell program is that a Haskell program only has one IO monad, but the universe seems to have many subjective observers in it. Having multiple IO monads would be a problem for a Haskell program because the IO monad defines how the program is actually evaluated - there's only one "real universe" for it to run in. But there's no problem having multiple non-IO monads - if the monads can't communicate with each other through the outside world (only through the program) you can have as many of them as you like. Since people can't communicate with each other except through the physical universe, there's no problem here.
Does this mean that one observer in the universe is priviliged to be the "IO monad" whilst everyone else is a p-zombie? From the point of view of that observer, it certainly seems like that is a possible way of thinking about it, but since there's no objective difference between an IO monad and a non-IO monad (as long as the monads only communicate objectively), I'm not sure the distinction is meaningful.
[...] observers then it seems to make a mockery of the very idea of an objective reality. Just as the IO Monad theory of subjective experience has no problems with observers disagreeing on matters that make no difference in an objective [...]