You do not need to change the state of your example. To “add a bookmark”, you can create a new bookmark list that has the same contents as the old list, but with one new entry. This is how most immutable programs work; instead of making changes to an existing object graph, you simply create a new object graph that reflects the new state of the world. When everything is unchanged, it is easy to distribute large portions of object plots between the "old" and "new" versions.
At one level deeper in your example, suppose a “browser” is a data structure object with the following information: current web page, user home page, and bookmark list. This can be represented in memory as a tree that looks something like this:
browser = { curPage --> "http://current" homePage --> "http://home" favorites --> { data --> "http://firstFav" next --> { data --> "http://secondFav" next --> null } } }
Now the AddFavorite function will accept such a data structure as input and return a new data structure, for example,
browser = *{ curPage --> "http://current" homePage --> "http://home" favorites --> *{ data --> *"http://newFav"* next --> { data --> "http://firstFav" next --> { data --> "http://secondFav" next --> null } } }* }*
Bits marked with the '*' sign are new objects - there is a new linked node list in front of the favorites containing a new line, and the browser structure itself is new (this should be because it has a new “Favorites”).
You can model all the calculations "stateful" like this, as functions that take in the "previous world" as input and return the "next world" as output; it is the essence of state monads in a language such as Haskell.
Brian
source share