함수형 프로그래밍 구현 (map filter reduce / go pipe curry )

KHW·2021년 8월 11일
0

Javascript 지식쌓기

목록 보기
70/95
post-custom-banner

map / filter / reduce

const products = [
  { name: "반팔티", price: 15000 },
  { name: "긴팔티", price: 20000 },
  { name: "휴대폰케이스", price: 15000 },
  { name: "후드티", price: 30000 },
  { name: "바지", price: 25000 },
];

const map = (f, iter) => {
  let res = [];
  for (const a of iter) {
    res.push(f(a));
  }
  return res;
};

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

const filter = (f, iter) => {
  let res = [];
  for (const a of iter) {
    if (f(a)) res.push(a);
  }
  return res;
};

console.log(filter((p) => p.price < 20000, products));

const reduce = (f, acc, iter) => {
  if (!iter) {
    iter = acc[Symbol.iterator]();
    acc = iter.next().value;
  }
  for (const a of iter) {
    acc = f(acc, a);
  }
  return acc;
};

console.log(
  reduce((total_price, product) => total_price + product.price, 0, products)
);

go

코드를 값으로 다루어 표현력 높이기
즉시, 어떤값을 평가

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

go(
  0,
  (a) => a + 1,
  (a) => a + 10,
  (a) => a + 100,
  console.log
);
//111

pipe

함수를 리턴하는 함수
함수들이 나열되어있는 합성된 함수를 만듬

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

go(
  0,
  (a) => a + 1,
  (a) => a + 10,
  (a) => a + 100,
  console.log
);

const f = pipe(
  (a) => a + 1,
  (a) => a + 10,
  (a) => a + 100
);

console.log(f(0));

go를 사용하여 표현을 명확히 하기

  • go를 사용하지 않았을 때
console.log(
  reduce(
    add,
    map(
      (p) => p.price,
      filter((p) => p.price < 20000, products)
    )
  )
);
  • go를 사용했을때
go(
  products,
  (products) => filter((p) => p.price < 20000, products),
  (products) => map((p) => p.price, products),
  (prices) => reduce(add, prices),
  console.log
);

이전 매개변수의 결과 값을 다음 매개변수 함수로 넣어 처리하여 가독성을 높였다.


curry

const curry = (f) => (a, ..._) =>
  _.length ? f(a, ..._) : (..._) => f(a, ..._);

const mult = curry((a, b) => a * b);
console.log(mult(1)(2));		//2
console.log(mult(1));			//[Function (anonymous)]

mult(1)은 curry((a,b) => a*b)(1)과 같고 이는
f가 (a,b) => a*b이고 a는 1로 ..._는 없으므로
함수가 리턴되고

mult(1)(2)는 curry((a,b) => a*b)(1)(2)과 같고 이는
f가 (a,b) => a*b이고 a는 1로 ..._는 2이므로
f(1, 2)인 즉 , (1,2)=>1*2가 실행된다.

curry 분석하기

const curry = (f) => (a, ..._) => {
  console.log(a, _, _.length, ..._);
  return _.length ? f(a, ..._) : (..._) => f(a, ..._);
};

/*
const curry = (f) => (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
 */

const mult = curry((a, b) => {
  console.log(a, b);
  return a * b;
});


console.log(mult(1)(2)); // _와 함께 다음 실행
// 1 [] 0
// 2

console.log(mult(1));
// 1 [] 0
// (..._) => f(a, ..._)

console.log(mult(1, 2)); // 받아 둔 함수 즉시 실행
// 1 [2] 1
// 2          => f(a, ..._) = f(1,2) = (1,2) => a*b

mult(1)는 (..._) => f(a, ..._)를 반환하면서 나머지 인자가 있다면 이를 진행하는 것이고 즉, mult(1)(2)는 나머지 인자인 2가 있으므로 f(1,2)를 진행한 2가 리턴된다.

정리

go : , 형태로 연속된 처리
pipe : 첫번째 값을 따로 처리
curry : 같은 매개변수 처리를 대신 해주는 역할

profile
나의 하루를 가능한 기억하고 즐기고 후회하지말자
post-custom-banner

0개의 댓글