I presume this is referring to the data structure that Evan posted? I was also trying to understand it, and yes, I think it is used as you describe; it marks a node in the tree with a focus and records a path that you can use later to walk back to that node.
Comparing that with with the Tree.indexedMap approach, it will be more efficient. This is due to the way indexedMap will walk the entire tree each time - the TreeExplorer will walk you more directly back to the node of interest. Provided the tree is balanced indexedMap will be O(n) but TreeExplorer will be O(log n). The zippers way will be similar in efficiency to TreeExplorer - it gives you the node of interest at zero cost but you still have to turn the zipper back into a tree with O(log n) cost. Note also, this assumed a balanced tree. A list can be viewed as a completely unbalanced tree so all the costs are O(n) worst case.
I think as you walk a tree you could maintain a list of all your path choices to get to a particular focus with this data structure:
type SignPost
= BranchL
| BranchR
| Focus -- Don't really need this as end-of-list implies it.
type alias TreePath = List SignPost
(Trees displayed in a UI not likely to be binary, so type alias TreePath = List Int is more realistic).
Then you would pass the TreePath with the Msg as a way of remembering how to get back to the node of interest.
The TreeExplorer and zipper techniques both suffer from the problem that they capture the tree and pass it with the message - meaning if two msgs are triggered against the same model the second update against the tree will obliterate the first one. Tree.indexedMap and TreePath above do not have this problem.
Tree.indexedMap and TreePath avoid the stale update problem when altering the content of nodes in the tree without changing its structure. If nodes are added, removed or moved on one update, a second stale update may not find its way back to the correct node. This could lead to an intermittent bug where the wrong node is updated but the program continues to run unaware of the error. This could be solved by adding unique ids on all the nodes and checking the correct node has been found prior to making the update - what would you do in that case? simply discard that event? I also think that the unique ids could be embedded into a re-usable data structure in such a way that you donāt have to re-implement this each time.
Yes, that is correct.
We should also look at the memory cost of these approaches, but Iāll save that for later unless someone else figures it outā¦