Pure function (純粋関数)とは

Pure function (純粋関数)とは

Reduxを学習している際にPure Functionsという単語を見かけ、調べたことを議事録として残します。
LispやHaskellなどの言語を学んでいる訳でないので深掘りした内容ではないです。

結論

純粋関数は
– 同じ入力が与えられればいつも同じ結果を返す
– 副作用を生み出さない
– 純粋関数を理解するためにはミュータブルとイミュータブルへの理解が必要になる

純粋関数・非純粋関数のコード例

純粋関数

純粋関数は副作用を生み出さないので、変数outputが返す値は予測通りのinputに”風呂洗い”を追加したオブジェクトになる。
const newTodos = […todos, text];
…はスプレッド演算子という構文で、引数に持つtodos配列をコピーしている。
配列だけでなくオブジェクトにも使用可能。

function addTodo(todos, text) {
  const newTodos = [...todos, text];
  return newTodos;
}
const input = ["早起き", "ジム", "洗濯", "犬の散歩"];
const output = addTodo(input, "風呂洗い");

console.log(input) //  ["早起き", "ジム", "洗濯", "犬の散歩"]
console.log(output) // ["早起き", "ジム", "洗濯", "犬の散歩", "風呂洗い"]

非純粋関数

下記の例は非純粋関数なので、input・output両方とも同じ値を返す。

function addTodo(todos, text) {
  todos.push(text);
  return todos;
}
const input = ["早起き", "ジム", "洗濯", "犬の散歩"];
const output = addTodo(input, "風呂洗い");

console.log(input); // ["早起き", "ジム", "洗濯", "犬の散歩", "風呂洗い"]
console.log(input); // ["早起き", "ジム", "洗濯", "犬の散歩", "風呂洗い"]

JavaScriptのミュータブル・イミュータブル

純粋関数を調べる上で感じたのはミュータブル・イミュータブルへの理解だと感じたので、JavaScriptのミュータブル・イミュータブルについてざっと纏めます。

以下の記事を参考にしました。
https://qiita.com/makotoo2/items/fc3a617882916f9775f5
https://qiita.com/migi/items/3417c2de685c368faab1

  • ミュータブル(変更可能)
    オブジェクト、配列、関数
  • イミュータブル(変更不可能)
    文字列、数値、シンボル、真偽値、null、undefined

イミュータブル

イミュータブル(immutable)はそのまま和訳すると「不変」です。
自分は変更不可能と捉えています。

let string1 = 'hi';

let string2 = string1; // ここで代入

string2 = string2 + 'how are u';

console.log(string1) // hi

console.log(string2) // hi how are u

文字列はイミュータブルなのでstring1を代入したstring2を変更してもstring1には影響を与えません。

ミュータブル

配列に値を追加する
const array1 = ["sample1", "sample2"];
const array2 = array1; // ここで代入
array2.push("sample3");

console.log(array1); // ["sample1", "sample2", "sample3"]
console.log(array2); // ["sample1", "sample2", "sample3"]

配列の値を削除する
const array1 = ["sample1", "sample2"];
const array2 = array1;
array2.splice(1, 1);

console.log(array1); // ["sample1"]
console.log(array2); // ["sample1"]

配列はミュータブル(変更可能)であるのでarray2を変更するとarray1までも変更がされます。
ミュータブルは参照した値の「状態」も変更します。

オブジェクト・配列をイミュータブルのように扱う

JavaScriptの新しい構文でスプレッド構文というのがあります。この構文を利用する事でオブジェクト・配列をイミュータブルのように扱うことが出来ます!

const object1 = {name: 'kuma', age:23};

const object2 = {...object1}; // {name: 'kuma', age:23}

object2.name = 'pon';
object2.age = 24;

console.log(object1) // {name: "kuma", age: 23}
console.log(object2) // {name: "pon", age: 24}

配列の追加はpushでなく以下の様にすることで新しい配列array2が返されます。

スプレッド構文を使用することでobject1のコピーがされ新しいオブジェクトobject2が作成されます。


const array1 = ["sample1", "sample2"];

const array2 = [...array1, "sample3"] // ["sample1", "sample2", "sample3"]

他にもfilterやmapを使用する事で新しい配列を生成しイミュータブルの様に扱うことが可能です。

以上のことを踏まえて純粋関数・非純粋関数の他のコード例を示す。

純粋関数(削除処理)

function deleteTodo(todos, position) {

  const newTodos = todos.filter((todo, index) => index !== position);

  return newTodos;

}

const input = ["早起き", "ジム", "洗濯", "犬の散歩"];

const output = deleteTodo(input, 3);

console.log(input) // ["早起き", "ジム", "洗濯", "犬の散歩"]

console.log(output) // ["早起き", "ジム", "洗濯"]

非純粋関数(削除処理)

function deleteTodo(todos, position) {

  todos.splice(position, 1);

  return todos;

}
const input = ["早起き", "ジム", "洗濯", "犬の散歩"];

const output = deleteTodo(input, 2);

console.log(input); //["早起き", "ジム", "犬の散歩"]

console.log(output); //["早起き", "ジム", "犬の散歩"]