开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜