Bidirectional reference with case classes
Is it possible to implement a bi-directional tree in a case class. This seems like it should be easy, but I'm getting stumped
case class Node(name:String, parent:Option[Node], children:List[Node])
I want to add a child (and get a new root) -- something like
def addChild(n:String):Node = {
Node(name, parent, Node(n, Some(this), Nil)::children)
}
But that won't work because the "parent" in the child will no longer refer to the Node which lists the child as a child. Is this possible with immutable lists and case classes?
Based on answer given below
case class Node(name: String, parent: () => Option[Node], children: List[Node]) {
def makeChild(name: String) = {
lazy val newParent:Node = Node(this.name, this.parent开发者_JAVA技巧, kid :: this.children)
lazy val kid:Node = Node(name, () => Some(newParent), Nil)
newParent
}
}
I asked the same question to @jamesiry on Twitter recently :-).
His answer:
sealed abstract class Tree[T]
case class Node[T](left : Tree[T], right : Tree[T]) extends Tree[T]
case class Leaf[T](value : T, parent : () => Tree[T]) extends Tree[T]
def make = {
lazy val root = Node(left, right)
lazy val left : Leaf[Int] = Leaf(1, () => root)
lazy val right : Leaf[Int] = Leaf(2, () => root)
root
}
Just a note: think if case classes are a good option for you to represent a tree.
Since case classes are value types, the only way to return parent is to return a copy of the parent, including a copy of the full subtree. Then if you for example enumerate its children, you will again get copies of the full subtrees.
If you want to do some replacements in the tree, e.g. replace a node on some deeper level, the only way again is to make a copy of the full tree and throw away the old tree.
This all seems a bit clumsy, but for example lift-json uses case classes to represent JSON ASTs, so it might not be that much of a problem. Not sure how good Scala is at reference sharing when copying. Maybe someone can comment?
If you do want to use case classes, the answer above with lazy evaluation is correct.
精彩评论