This is the idea of functional programming. Everything is immutable, no function call is allowed to have side-effects. The only way to mutate complex objects, like in your example, is to re-create the parent objects.
Now the question is how to alter the program state. Therefore, we first think about the stack. It contains the values of all local variables as well as the value of all parameters to the called functions. We can create new values by calling new functions. We can discard values by returning from a function. Thus, we can mutate the program state by calling functions. However, it is not always possible to return from the function to discard its local variables, because we might want to only discard some of the local variables, but need to keep the value of others for further operations. In this case, we simply cannot return, but we need to call another function and pass only some of the local variables to it. Now, to prevent a stack overflow, functional languages have a feature which is called tail call optimization, which is able to remove unnecessary entries from the call stack. An entry of the call stack is unnecessary if the only thing that is left to do for the associated function is to return the value of the function that was called by itself. In this case, there is no point in keeping the call stack entry. By removing the unnecessary call stack entry, the values of the otherwise unused local variables is discarded. You might want to read about it here. Also, tail recursion is related to this.
Again, this is the idea of purely functional programming languages like Haskell. It is really nice that everything is immutable, however these languages have their only issues and their own ways to handle these. For example, Monads (and therefore higher kinded types) are available in these languages, but are rarely seen in imperative/object oriented programming languages.
I like to have immutable values at the leaves of my program memory. However, the code to compose these immutable values, which actually forms the application logic does contain mutable state. For me, this combines the advantages of both worlds. However, this seems to be a matter of preference.