A transverse tree similar to an object in tail recursive mode in scala

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
}

, ?

+4
2

(.. ). , , , , , . , . , .

// Simplified version of your Node; let ignore the value for now
case class Node(value: Unit, children: List[Node])
var counter = 0
def traverseNodeAccum(node: Node)(acc: List[Node]): Unit = {
  counter += 1
  (node.children, acc) match {
    case (Nil, Nil) => 
      ()
    case (Nil, x :: rest) =>
      traverseNodeAccum(x)(rest)
    case (child :: otherChildren, xs) => 
      traverseNodeAccum(child)(otherChildren ++ xs)
  }
}

- , ( , ). , case class .

+1

, , @badcook:

def matchNodes(goldSentence: LabeledSentence): Int = {
  @inline def condition(n: Node): Boolean = ???

  @tailrec
  def match0(acc:Int, n: Node)(queue:Seq[Node]): Int = {
    val count = if (condition(n)) acc + 1 else acc

    (queue: @switch) match {
      case head +: tail =>
        match0(count, head)(head.left ++ head.right ++ tail)
      case Nil =>
        count
    }
  }

  match0(0, this)(left ++ right)
}
+2

Source: https://habr.com/ru/post/1659314/


All Articles