I am trying to make a function that traverses an object with a tree as a structure in a tail recursive way, but so far I cannot write code that does this.
My tree object:
case class Node(lex: String,
position: Int,
posTag: String,
var dependency: Int = -1,
var left: Vector[Node],
var right: Vector[Node])
Version 1, tail recursive (not working)
So far I have tried the simplest form:
def matchNodes(goldSentence: LabeledSentence): Int = {
def condition(n: Node): Boolean = ???
@tailrec
def match0(acc: Int, n: Seq[Node]): Int =
(n: @switch) match {
case head :: tail => {
if (condition(head)) {
match0(acc + 1, tail)
} else {
acc
}
}
case _ => acc
}
match0(0, left) + match0(0, right)
}
The above code is tailrec, but not traversing the whole tree, only the first level.
Version 2, tail recursive (not working)
Another way:
def matchNodes(goldSentence: LabeledSentence): Int = {
@inline def condition(n: Node): Boolean = ???
def sumAcc(nodes: Vector[Node]): Vector[Node] = nodes match {
case head +: tail => sumAcc(head.left ++ head.right ++ tail)
case _ => nodes
}
@tailrec
def match0(acc: Int, n: Seq[Node]): Int =
(n: @switch) match {
case head :: tail => {
if (condition(head)) {
match0(acc + 1, tail)
} else {
acc
}
}
case _ => acc
}
val flatTree = sumAcc(right ++ left)
match0(0, flatTree)
}
Here I tried to add all the nodes into one Vector[Node], but for some reason the expected result after processing the tree is incorrect.
Version 3, no Fractal tail (working)
The last code I tried is not tail recursive, but it is the only one that calculates the correct result:
def matchNodes(goldSentence: LabeledSentence): Int = {
var correctRoots = 0
val position:Int = this.position
val dep:Int = dependency
val tag = goldSentence.tags(position)
if (goldSentence.dep(position) == dep || Constants.punctuationTags.contains(tag))
correctRoots += 1
if (right.nonEmpty)
for (r <- right)
correctRoots += r.matchNodes(goldSentence)
if (left.nonEmpty)
for (l <- left)
correctRoots += l.matchNodes(goldSentence)
correctRoots
}
, ?