I have a pseudo-function as below
let counter = 0;
function createNewFile() {
const fileName = `book_${counter++}`;
//...write file or whatever
};
The above function createNewFile definitely not ideal as it relies on external variable counter which may be changed unexpectedly. I'm thinking to reduce the chances of that happening, by closures and IIFE as below
const counter = (() => {
let counter = 0;
return () => counter++;
})();
console.log(counter())
console.log(counter())
/*
function createNewFile() {
const fileName = `book_${counter()}`;
//...write file or whatever
};
*/
The code above served the purpose which now the counter is arguably "harder" to be changed "accidentally".
However, I'm wondering from functional programming perspective, how can we improve both the function counter and createNewFile? Because clearly both violated pure function rules, where both function are not giving same output on every single execution, I'm curious how to enhance the code given the use case?
Your function is concerned with two effects:
You can simply avoid local variables by passing them as arguments. The state is moved to the call stack. You cannot avoid all mutations using this techniques, though. For this reason functional programming often supplies persistent data structures, a clever form of immutability.
The I/O effect is harder to deal with. In Javascript I/O is often async hence promises are used to encode such computations. Unfortunately promises have a rather unprincipled semantics from a functional angle, so I am going to use a raw continuation type to show how to defer I/O effects under the hood:
function createNewFile(counter, data) {
const fileName = `book_${counter}`;
return k => {run: k(writeFile(fileName, data))}
};
const description = createNewFile(1, someData);
description.run(checkSuccess);
Instead of performing the effect we merely get back a description of this very action. The function is not particularly useful on its own. We need means to apply its result to other pure functions or to combine it with other descriptions without actually performing the effect, but this would go beyond the scope of this answer.