This is a very interesting question! As already noted, you must change the entire path from root to the node you want to change. Immutable cards are very similar, and you can learn something by looking at the Clojure PersistentHashMap .
My recommendations:
- Change
Tree to Node . You even call this node in your question, so this is probably the best name. - Pull
value to base class. Once again, you are talking about this in your question, so this is probably the right place for him. - In the replace method, make sure that if none of the
Node and its children are changed, do not create a new Node .
Comments are given in the code below:
// Changed Tree to Node, b/c that seems more accurate // Since Branch and Leaf both have value, pull that up to base class sealed abstract class Node(val value: Int) { /** Replaces this node or its children according to the given function */ def replace(fn: Node => Node): Node /** Helper to replace nodes that have a given value */ def replace(value: Int, node: Node): Node = replace(n => if (n.value == value) node else n) } // putting value first makes class structure match tree structure case class Branch(override val value: Int, left: Node, right: Node) extends Node(value) { def replace(fn: Node => Node): Node = { val newSelf = fn(this) if (this eq newSelf) { // this node value didn't change, check the children val newLeft = left.replace(fn) val newRight = right.replace(fn) if ((left eq newLeft) && (right eq newRight)) { // neither this node nor children changed this } else { // change the children of this node copy(left = newLeft, right = newRight) } } else { // change this node newSelf } } }
source share