Как преобразовать эту функцию в чистую функцию? - PullRequest
1 голос
/ 23 февраля 2020

У меня есть следующая функция.

const array = [1, 2, 3];

// Impure function

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

Это нечистая функция, потому что она мутирует глобальный массив. Итак, я подумал, что предоставление всего массива в качестве аргумента функции сделает функцию чистой.

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

Но я обнаружил, что она также имеет побочные эффекты.

, так что бы лучший подход, чтобы сделать его чистой функцией?

Ответы [ 3 ]

3 голосов
/ 23 февраля 2020

Внутри тела функции вы можете скопировать входной массив и добавить элемент в конец этого нового массива. Вы можете легко сделать это с помощью оператора распространения es6

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

, чтобы он не изменял глобальный массив и функция была чистой функцией.

2 голосов
/ 23 февраля 2020

Копирование массива для каждой операции невероятно неэффективно. В качестве альтернативы вы можете отложить нечистую операцию pu sh до времени выполнения (обозначается main на следующем рисунке) и скопировать массив только один раз для каждой композиции:

/*** 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
0 голосов
/ 24 февраля 2020

Самым простым решением является использование чисто функциональной структуры данных , такой как список.

// 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));

Обратите внимание, что хотя функция toArray использует мутацию, она все же чиста, потому что:

  1. Возвращает один и тот же выход для тех же входов .
  2. У него нет никаких побочных эффектов.

Я объяснил точно, что означает, что функция считается чистой в более раннем ответе .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...