Think about a mutable variable. In an imperative program X can start with A, then become B, then become C, etc. In a functional program, you can say that X doesn't change, instead there's really a subscript: X0=A, X1=B, X2=3. That is, you're projecting the time dimension, which is implicit, linear, etc, on to a space dimension: The name of the variable expands from ["x"] to ["x", 1] etc.
Monads are the (an?) ultimate exploration of this idea. You project the timeline of the entire world on to a space dimension. Each "bind" operation builds up a new world and you can have many forks of the world, as it's just a model, not the world itself. This model doesn't do anything until you "run" the monad by handing it off to some higher level interpreter.
As for constraint satisfaction, check out Sussman's talk "We Really Don't Know How To Compute" <https://www.youtube.com/watch?v=O3tVctB_VSU> - Even though they implement the propagator networks with a message queue and a single thread, you could in theory run each propagator in parallel, sending messages back and forth.
Writing another comment, I had the thought that time is still present in the functional paradigm, though not in the same way as it typically presents in the imperative paradigm. This is a great way of thinking about it, thanks.