함수형 프로그래밍(FP) 실습

Dan·2022년 3월 18일
0

실무공부

목록 보기
3/12
post-thumbnail

이 글은 함수형 프로그래밍과 명령형 프로그래밍의 차이점을 학습하기 위해 인프런 함수형프로그래밍 강의를 따라하며 개인적으로 정리한 내용이다.

add_maker 예제

function add_maker(a) {
  return function(b){
    return a+b;
  };
}

const add10 = add_maker(10); // f(b) { return a + b };
conosle.log(add10(20)); // 30

const add5 = add_maker(5); // f(b) { return a + b };
console.log(add5(10)); // 15

const add15 = add_maker(15); // f(b) { return a + b };
console.log(add15(10)); // 25

예제에서 add_maker이란 함수를 add10이란 이름으로 변수로 할당하고 콘솔로 찍어보면 function(b) 라는 함수를 리턴하는 것을 볼 수 있다. 하지만 add10이란 변수에 20이라는 숫자를 인자 값으로 넘어서 호출을 하게되면 30이라는 숫자가 출력되는 것을 볼 수 있다. 분명 인자 값으로 20을 넘겼는데 어떻게 이전에 넣었던 10과 합쳐진 30이라는 값으로 반환 되는 것일까? 바로 클로저 때문이다.

  • 클로저: 함수(add_maker)의 호출이 끝난 시점에도 a라는 변수를 기억하고 있다가 함수의 리턴문의 또 다른 함수(클로저)가 a라는 변수를 접근 할 수 있는데 이 함수를 클로저라고 부른다.

  • 일급함수: 함수를 리턴하고 있으므로 일급 함수 개념이 쓰였다.

  • 순수함수: add_maker의 내부 함수인 클로저는 순수 함수이다. 동일한 참조값인 a에 b를 더해 항상 같은 결과를 반환하기 때문이다.

예제에서 본 것처럼 함수에 값을 넣고 부수효과가 없는 프로그래밍을 함수형 프로그래밍이라고 한다.

명령형 프로그래밍 ➡ 함수형 프로그래밍으로 전환해보기

예제를 통해 명령형 코드를 함수형 코드로 바꿔보자.

const users = [
  { id: 1, name: "ID", age: 36 },
  { id: 2, name: "BJ", age: 32 },
  { id: 3, name: "JM", age: 32 },
  { id: 4, name: "PJ", age: 27 },
  { id: 5, name: "HA", age: 25 },
  { id: 6, name: "JE", age: 26 },
  { id: 7, name: "JI", age: 31 },
  { id: 8, name: "MP", age: 23 },
];

명령형 프로그래밍

// 명령형 코드

// 1) 30세 이상인 users를 찾자.
const temp_users = [];
for(let i = 0; i < users.length; i++) {
  if(users[i].age >= 30) {
    temp_users.push(users[i]);
  }
}
console.log(temp_users);

// 2) 30세 이상인 users의 names를 수집한다.
const names = [];
for(let i = 0; i < temp_users.length; i++){
  names.push(temp_users[i].name);
}
console.log(names);

// 3) 30세 미만인 users를 찾자.
const temp_users2 = [];
for (let i = 0; i < users.length; i++) {
  if (users[i].age < 30) {
    temp_users2.push(users[i]);
  }
}
console.log(temp_users);

// 4) 30세 미만인 users의 ages를 수집한다.
const ages = [];
for (let i = 0; i < temp_users2.length; i++) {
  ages.push(temp_users2[i].age);
}
console.log(ages);

_filter, _map으로 리팩토링

  • 명령형 코드에서 _filter를 이용해 1), 3)의 중복을 없애고 , _map을 이용해 2) , 4)의 중복을 없애보자.
function _filter(list, predi){
  const new_list = [];
  for(let i = 0; i < list.length; i++){
    if(predi(list[i])){
      // 조건에 해당하는 값만 새로운 리스트에 넣어준다.
      new_list.push(list[i]);
    }
  }
  return new_list;
}

function _map(list, mapper){
  const new_list = [];
  for(let i = 0; i < list.length; i++){
    // 조거엔 해당하는 값만 새로운 리스트에 넣어준다.
    new_list.push(mapper(list[i]));
  }
  return new_list;
}

const over_30 = _filter(users, function (user) {
  return user.age >= 30;
});
console.log(over_30);

const under_30 = _filter(users, function (user) {
  return user.age < 30;
});
console.log(under_30);

const over_30_names = _map(over_30, function (user) {
  return user.name;
});
console.log(over_30_names);

const under_30_ages = _map(under_30, function (user) {
  return user.age;
});
console.log(under_30_ages);

// users가 아닌 다른 데이터도 _filter를 활용할 수 있다.
/*
console.log(_filter([1,2,3,4], function(num){ return num % 2; }));
console.log(_filter([1,2,3,4], function(num){ return !(num % 2); }));
*/
  • 받아둔 predi함수에 user[i]를 적용하는 식으로 동작하는데 이를 응용형 프로그래밍 이라고한다.

    응용형 프로그래밍: 함수가 함수를 받아서 원하는 시점에 해당 함수가 알고 있는 인자를 적용하는 식의 프로그래밍

// 함수형 프로그래밍에서는 위 코드와 같은 대입문을 줄이고 아래처럼 함수를 중첩하는 방식을 많이 쓴다.

console.log(
  _map(
    _filter(users, function (user) {
      return user.age >= 30;
    }),
    function (user) {
      return user.name;
    }
  )
);

console.log(
  _map(
    _filter(users, function (user) {
      return user.age < 30;
    }),
    function (user) {
      return user.age;
    }
  )
);

참고자료

https://pul8219.github.io/javascript/js-fp-step49/

profile
만들고 싶은게 많은 개발자

0개의 댓글