Processing a list of pairs of items using promises and functional programming I posted an answer on StackOverflow which I believed to be adherent to the principles of Functional Programming. 

However, I was told by the original asker that it was not 'functional' as my function used an internal variable oldData which kept track of results. 

I believe that the code still satisfies the paradigms of functional programming as it does not mutate it's arguments, does not use globals and has no side effects (assuming action is not a network call)

Is the function process() violating the principles of functional programming? If so, how would I fix it?



var items = [
    ["item1", "item2"],
    ["item3", "item4"],
    ["item5", "item6"],
    ["item7", "item8"],
    ["item9", "item10"]
]

function action(item) {
    return new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve(item + ":processed");
        }, 100)
    });
}

function process(items) {
  return items.reduce((m, d) =&gt; {
    const promises = d.map(i =&gt; action(i));
    let oldData;
    return m.then((data) =&gt; {
        oldData = data;
        return Promise.all(promises);
      })
      .then(values =&gt; {
        //oldData.push(...values);
        oldData.push.apply(oldData, values);
        return Promise.resolve(oldData);
      })
  }, Promise.resolve([]))
}

process(items).then(d =&gt; console.log(d))

//Prints:

// ["item1:processed","item2:processed","item3:processed","item4:processed","item5:processed","item6:processed","item7:processed","item8:processed","item9:processed","item10:processed"]




The original asker suggested that I update my code to use concat instead of push to create immutable arrays every time to make this properly functional. Does that make sense?
Does this function break the paradigm of functional programming in JS?


Short answer: It depends

One common response I get from Software Engineering SE on this topic is you don't have to be pure all the time. A function can still act functional even if the implementation isn't written in a functional manner. Take for example the following:

// All return an array with numbers starting from s to e with no
// side-effects and takes all input from args. The first one is
// obviously not "functional" but works just as well as the others.

function range(s, e){
  const array = []
  for(let i = s; i &lt; e; i++){
    array.push(s)
  }
  return array
}

function range(s, e){
  return Array(e - l).fill(null).map((v, i) =&gt; s + i)
}

function range(s, e){
  return s == e ? [] : [s, ...range(s + 1, e)]
}


Striking a balance between ideal and practical is also a deciding factor. For instance, recursion is not a foreign concept in JS. But historically, due to stack size limits, loops became more prevalent. You can safely assume people can read loops better than recursion, and are therefore more likely to understand the first sample than the other two.



It looks like the purpose of process function is to batch-process arrays of items. This can be done with recursion. The idea is to process the current item, then concat the results of the next call, which does the same thing until there's nothing in the array. If you use Node or have Babel to transpile, you can use async/await to simplify the syntax.

const process = async (i) =&gt; {
  if (!i.length) return []

  const r1 = await Promise.all(i[0].map(action))
  const r2 = await process(i.slice(1))

  return [...r1, ...r2]
}


If you can't do async/await, here's an expanded version with regular promise syntax.

function process(i) {
  if (!i.length) return Promise.resolve([]) 

  return Promise.all(i[0].map(action)).then(function(r1) {
    return process(i.slice(1)).then(r2 =&gt; r1.concat(r2))
  })
}