0

I have the following function.

const array = [1, 2, 3];

// Impure function

function addElementToArray(element) {
  array.push(element);
}

This is an impure function because it mutates the global array. So, I thought that giving the whole array as a function argument will make the function pure.

function addElement(array, element) {
  array.push(element);
}

But, I found that it has also side effects.

so, what would be the best approach to make it a pure function?

Ashik
  • 2,888
  • 8
  • 28
  • 53
  • 1
    The best approach would be to use a functional data structure such as a list. Then you can cons a new element onto the list, which is a constant time operation. – Aadit M Shah Feb 23 '20 at 13:52
  • @AaditMShah the OP is looking for a pure-function implementation; that still wouldn't be pure as it'd still be mutating input, regardless of complexity. – avocadatoria Feb 23 '20 at 20:42
  • @avocadatoria No, it wouldn't be mutating the input. It would construct a new list with the new element as the head and the old list as the tail. Functional data structures are immutable. – Aadit M Shah Feb 24 '20 at 02:29
  • 2
    It's unclear what the goal is here. The easiest approach to make a function pure is to drop all statements with the undesired side effects, so `function addElementToArray(element) {}`. So what do you actually want to use the array for? That's the important question, and the answer will guide you on what function and data structure you need. – Bergi Feb 24 '20 at 03:12
  • @AaditMShah got it; I misunderstood what you were suggesting. – avocadatoria Feb 24 '20 at 03:34
  • @Bergi I like how you don't read between the lines. You interpret the question quite literally. It's always fun to read your comments and answers. =) – Aadit M Shah Feb 24 '20 at 05:30

4 Answers4

3

Inside the body of the function, you can copy the input array and append the element at the end of that new array. you can easily do that with es6 spread operator

function addElementIntoArray(a, element) {
  // returning a brand new array
  return [...a, element];
}

so that, it will not mutate the global array and the function will be a pure function.

Ashik
  • 2,888
  • 8
  • 28
  • 53
2

Copying the array for every operation is incredible inefficient. Alternatively you can defer the impure push operation until runtime (referred to as main in the following sketch) and copy the array only once per composition:

/*** pure ***/

const Defer = thunk => ({get runDefer() {return thunk()}});

const defMap = f => tx =>
  Defer(() => f(tx.runDefer));

const pipe = g => f => x => f(g(x));

const catDef = xs => ys =>
  Defer(() => xs.concat(ys)); // pass [] to copy the array

const pushDef = x => tx =>
  defMap(xs => (xs.push(x), xs)) (tx);

const xs = ["foo", "bar"];

const main = pipe(
  pushDef("baz"))
   (pushDef("bat"))
    (catDef(xs) ([]));

/*** impure ***/

console.log(
  main.runDefer); // runs the side effect within the composition only at runtime

console.log(xs); // no global side effect
1

Using the push method, you can simply make a local copy of array inside the function, push the item into the copied array, and then finally return the array. Here's is the code.

function addNewelement(array,item){
    const newArr = array.slice();     
    newArr.push(item);
    return newArr;
}

Now, it will not change the global array.

Aakash Sr
  • 41
  • 1
  • 6
0

The easiest solution is to use a purely functional data structure such as a list.

// empty :: List a -- an empty list of any type
const empty = null;

// cons :: (a, List a) -> List a -- add an element to the list
const cons = (head, tail) => ({ head, tail });

// toArray :: List a -> [a] -- convert the list to an array in reverse
const toArray = list => {
    if (list === empty) return [];
    const array = toArray(list.tail);
    array.push(list.head); // although we use mutation here, yet toArray is pure
    return array;
};

// example :: List Int
const example = cons(3, cons(2, cons(1, empty)));

// [1, 2, 3] :: [Int]
console.log(toArray(example));

Note that although the toArray function uses mutation, yet it is pure because:

  1. It returns the same output for the same inputs.
  2. It does not have any side effects.

I've explained precisely what it means for a function to be considered pure in an earlier answer.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299