Node.js/JS

[JavaScript] 이터러블 객체와 순회 함수 응용

턴태 2023. 4. 30. 12:12
const product = [
	{ name: '반팔티', price: 15000, quantity: 1 },
    { name: '긴팔티', price: 20000, quantity: 2 },
    { name: '핸드폰케이스', price; 15000, quantity: 3 },
    { name: '후드티', price: 30000, quantity: 4 },
    { name: '바지', price: 25000, quantity: 5 },
];

const go = (...args) => reduce((a, f) => f(a), args);

여기서 수량을 모두 합하고자 할 때, go를 통해 연속적으로 함수를 실행할 수 있다.

go(
	products,
	map(p => p.quantity),
    console.log
);

위의 결과는 [1, 2, 3, 4, 5]라는 결과로 귀결된다.

이때, 정수형 배열이 반환되었기 때문에 reduce를 통해서 총 합을 계산할 수 있다.

go(
	products,
    map(p => p.quantity),
    reduce((a, b) => a + b),
    console.log
);

결과로는 15의 총합이 나오는 것을 볼 수 있다.

 

이를 함수로써 사용할 수 있다. 예를 들어서 quantity를 키로 가지는 객체 배열에 대해서는 동일한 로직으로 처리하여 총합을 계산하는 함수를 완성할 수 있다.

products가 첫 번째 인수로 이 자리를 새로운 함수의 인자로서 전달하면 되기 때문이다.

const total_quantity = products => go(products,
	map(p => p.quantity),
    reduce((a, b) => a + b);

이때, go의 첫 번째 인자로 products를 넣는다는 것은 기존에 만들었던 pipe 함수로도 대체할 수 있음을 보여준다.

const pipe = (...fs) => (a) => go(a, ...fs);

const total_quantity = pipe(
	map(p => p.quantity),
    reduce((a, b) => a + b));
    
console.log(total_quantity(products));

위처럼 pipe는 내가 원하는 시점에 실행시킬 수 있는 함수이기 때문에, 첫 번째로 함수들을 받아놓은 다음, products를 인자로 하여 원하는 로직을 수행할 수 있다.

 

간단하게 응용하여, 수량과 가격을 합산해 총 값을 계산할 수도 있다.

const total_price = pipe(
	map(p => p.price * p.quantity),
    reduce((a, b) => a + b));

console.log(total_price(products));

이때, total_quantity와 total_price는 map과 reduce가 겹친다. 또한, 이 두 개의 함수는 특정 도메인에 종속된 함수이기 때문에 조금 더 추상화 레벨을 높이는 것이 좋다.

 

const add = (a, b) => a + b;

const sum = (f, iter) => go(
	iter,
    map(f),
    reduce(add));
    
console.log(sum(p => p.quantity, products));

조금 더 추상화를 하기 위해, map안에 들어가는 함수를 매개변수로 만들어서 원하는 함수를 집어 넣을 수 있다. 즉, 최종적으로 sum을 사용하면 아래와 같이 작성할 수 있다.

const total_quantity = products => sum(p => p.quantity, products)

console.log(total_quantity(products));

const total_price = products => sum(p => p.quantity * p.price, products);

console.log(total_price(products));

그런데 심지어 여기서 더 코드를 간결하게 할 수 있다. curry를 사용하는 방법이다.

const sum = curry((f, iter) => go(
	iter,
   	map(f),
    reduce(add)));
    
const total_quantity = products =>
	sum(p => p.quantity)(products);

 여기서 products를 받아서 그 인자를 다시 반환하는 함수의 인자로써 사용하기 때문에 단순히 우리가 원하는 함수만을 전달해 사용할 수 있다.

const total_quantity = sum(p => p.quantity);
const total_price = sum(p => p.price * p.quantity);

currying을 통해서 보조함수를 사용하겠다는 것으로 코드를 간결하게 만들 수 있다. 

 


출처: 인프런 함수형 프로그래밍과 JavaScript ES6+