Alejandro Alcalde
Alejandro Alcalde

Reputation: 6220

Substitute while loop with functional code

I am refactoring some scala code and I am having problems with a while loop. The old code was:

for (s <- sentences){
// ...
   while (/*Some condition*/){
      // ...
      function(trees, ...)
   }
}

I've have translated that code into this one, using foldLeft to transverse sentences:

sentences./:(initialSeed){
 (seed, s) =>
     // ...
     // Here I've replaced the while with other foldleft 
     trees./:(seed){
         (v, n) =>
             // ....
             val updatedVariable = function(...., v)
     }
}

Now, It may be the case that I need to stop transversing trees (The inner foldLeft before it is transverse entirely, for that I've found this question:

Abort early in a fold

But I also have the following problem:

As I transverse trees, I need to accumulate values to the variable v, function takes v and returns an updated v, called here updatedVariable. The problem is that I have the feeling that this is not a proper way of coding this functionality.

Could you recommended me a functional/immutable way of doing this?

NOTE: I've simplified the code to show the actual problem, the complete code is this:

val trainVocabulart = sentences./:(Vocabulary()){
  (vocab, s) =>
    var trees = s.tree
    var i = 0
    var noConstruction = false

    trees./:(vocab){
      (v, n) =>
        if (i == trees.size - 1) {
          if (noConstruction) return v
          noConstruction = true
          i = 0
        } else {
          // Build vocabulary
          val updatedVocab = buildVocabulary(trees, v, i, Config.LeftCtx, Config.RightCtx)

          val y = estimateTrainAction(trees, i)

          val (newI, newTrees) = takeAction(trees, i, y)

          i = newI
          trees = newTrees

          // Execute the action and modify the trees
          if (y != Shift)
            noConstruction = false

          Vocabulary(v.positionVocab ++ updatedVocab.positionVocab,
            v.positionTag ++ updatedVocab.positionTag,
            v.chLVocab ++ updatedVocab.chLVocab,
            v.chLTag ++ updatedVocab.chLTag,
            v.chRVocab ++ updatedVocab.chRVocab,
            v.chRTag ++ updatedVocab.chRTag)
        }
      v
    }
}

And the old one:

for (s <- sentences) {
  var trees = s.tree
  var i = 0
  var noConstruction = false
  var exit = false
  while (trees.nonEmpty && !exit) {
    if (i == trees.size - 1) {
      if (noConstruction) exit = true
      noConstruction = true
      i = 0
    } else {
      // Build vocabulary
      buildVocabulary(trees, i, LeftCtx, RightCtx)

      val y = estimateTrainAction(trees, i)

      val (newI, newTrees) = takeAction(trees, i, y)

      i = newI
      trees = newTrees

      // Execute the action and modify the trees
      if (y != Shift)
        noConstruction = false
    }
  }
}

Upvotes: 1

Views: 696

Answers (1)

jwvh
jwvh

Reputation: 51271

1st - You don't make this easy. Neither your simplified or complete examples are complete enough to compile.

2nd - You include a link to some reasonable solutions to the break-out-early problem. Is there a reason why none of them look workable for your situation?

3rd - Does that complete example actually work? You're folding over a var ...

trees./:(vocab){

... and inside that operation you modify/update that var ...

trees = newTrees

According to my tests that's a meaningless statement. The original iteration is unchanged by updating the collection.

4th - I'm not convinced that fold is what you want here. fold iterates over a collection and reduces it to a single value, but your aim here doesn't appear to be finding that single value. The result of your /: is thrown away. There is no val result = trees./:(vocab){...

One solution you might look at is: trees.forall{ ... At the end of each iteration you just return true if the next iteration should proceed.

Upvotes: 1

Related Questions