[CS/Functional programming] 함수형 프로그래밍

0
post-thumbnail

✅함수형 프로그래밍은 side effect를 배제하며 조합성을 강조하는 프로그래밍 패더다임이다.

  • side effect를 배제한다 => 순수 함수를 만든다. => 오류를 줄이고 안정성을 높인다.
  • 조합성을 강조한다 =>모듈화 수준을 높인다. => 생산성을 높인다.
  • 함수형 프로그래밍에서는 중복을 제거하거나 어떤 대상을 추상화할 때 함수를 사용하면 된다. 추상화의 단위가 함수이다.
  • 함수형 프로그래밍은 값을 만들어놓는게 아니라 함수를 통과하면서 값을 만들어 낸다.

1급 객체

Javascript의 함수는 일급객체이다.

1급 객체의 조건

  • 무명의 리터럴로 표현이 가능하다.
  • 변수나 자료 구조(객체, 배열 등)에 저장할 수 있다.
  • 함수의 매개변수에 전달할 수 있다.
  • 반환값으로 사용할 수 있다.

순수 함수

1. 순수 함수

  • input이 같으면 항상 동일한 output을 만드는 함수이다.
  • input외에 외부의 상태에 영향을 받지 않는다.
  • 리턴값 외에는 외부와 소통하는 것이 없다.
  • 평가 시점이 중요하지 않다.
  • 프로젝트 작업에서 유지보수가 쉽다.
  • output 계산에 전역변수를 사용하지 않는다.

Example 1

function greet(name){
  return "Hi, I'm" + name;
}
greet("jack"); //"Hi, I'm jack"

Example 2

var obj = { val : 10};
function add(obj, b) {
  return { val: obj.val + b }
}
console.log(obj.val); //10
add(obj, 20);
console.log(obj.val); //10
  • 순수 함수에서 객체의 값을 변형해 나갈 때 원래 있던 값은 그대로 두고, 새로운 값을 복사해서 원하는 모양을 만든다.

2.순수 함수가 아닌 함수 -side effect를 일으키는 함수

Example 1

var name = "jack";
var greeting = "Hi, I'm";
console.log(greeting + name); //"Hi, I'm jack"
  • name이나 greeting에 다른 값이 재할당되면 결과가 바뀔 수 있다.

Example 2

var c = 10;
function add(a,b){
  return a + b + c; 
}
console.log((add(10,2));
         

Example 3

var c = 20;
function add(a,b) {
  c = b;
  return a + b;
}
console.log(c); //20
console.log(add(20,30)); //50
console.log(c); //30
  • 외부 or 들어온 인자의 상태를 직접 바꾼다.

고차 함수

  • 함수를 값으로 다룰 수 있는 개념
  • 변수에 함수를 담을 수 있다.
  • 다른 함수를 input으로 받거나 함수를 output으로 반환하는 함수이기에 이경우 함수를 일종의 객체로 취급하게 된다.
  • 순수 함수를 조합해서 어떤 로직안에서 평가를 할 것인지를 정하면서 큰 로직을 만들어간다.
  • 함수를 인자로 받아서 원하는 시점에 사용한다.
  • 어떤 for문을 반복하면서 필요한 부분에서 받은 함수를 여러 번 실행하는 형태를 띄는 것이 함수형 프로그래밍이다.

고차 함수 예시(in JS 내장 함수)

  • Array.prototype.sort()
  • Array.prototype.forEach()
  • Array.prototype.map()
  • Array.prototype.filter()
  • Array.prototype.reduce()
  • Array.prototype.some()
  • Array.prototype.every()
  • Array.prototype.find()

Example 1

var f1 = function(a) { retrun a * a }
console.log(f1); //function(a) { retrun a * a }

Example 2

function f3(f) {
  return f();
}
console.log( f3(function(){return 10;}) ); //10

Example 3

function add_maker(a) {
  return function(b) {  //여기서 이 함수는 closure이기도 함 a라는 값을 이 함수에서 참고하기에 closure로서 a라는 함수를 기억할 수 있음. 또한 a라는 값을 참조할 뿐 변경하지 않기 때문에 순수 함수임 
    return a + b;
  }
}
var add = add_maker(10); //  함수가 할당됨
console.log(add(20));

Example 4

function makeAdjectifier(adjective) { 
  return function (string) {
    return adjective + "" + string;
  };
}

var coolifier = makeAdjectifier("cool");
coolifier("conference"); //"cool conference"

maekAdjectifier이라는 함수에 "conference"를 전달하면 "cool conference"가 나옴.

Example 5

✅함수형 프로그래밍에 자주 쓰이는 형식!

function f4(f1, f2, f3) {
  return f3(f1() + f2());
}
f4(
  function() {return 2;},
  function() {return 1;},
  function(a) {return a * a;}
  ); 
// 3*3한 결과인 9가 return 됨 

함수형 프로그래밍 작성시 주의 해야할 사항

1. 반복문을 피하자

for,while등의 반복하는 코드를 작성하기 보다 map, reduce, filter와 같은 고차 함수를 사용하자.


함수형 프로그래밍에서는 map을 이용해서 재료 목록과 '다지기' 함수를 전달하면 그 output으로 다져진 재료들의 목록이 나온다. 이후 reduce로 모든 재료 목록을 어떠한 방식(e.g. 샌드위치 제조)으로 결합할 수 있다. 또한 filter를 사용해서 싫어하는 재료를 뺄수도 있다.

2. immutable 데이터를 사용하자.

mutable

var rooms = ["H1", "H2", "H3"];
rooms[2] = "H4";
rooms; //["H1", "H2", "H4"]

만약 이런식으로 다른 곳에서 참조하고 있는 변수가 원본 데이터를 변경 시킨다면 이로 인해 발생한 버그들을 해결하기 어렵다.

immutable

var rooms = ["H1", "H2", "H3"];
var newRooms = rooms.map(function (rm) {
  if (rm === "H3") { return "H4"; }
  else {return rm;}
});
newRooms;//["H1", "H2", "H4"]
rooms; //["H1", "H2", "H3"]

예를 들어 위와 같이 배열 같은 데이터를 사용한다 했을 때 immutable 데이터의 문제는 immutable을 유지하기 위해 계속 사본을 생성해야 한다는 점이다. 만약 1개의 room 정보를 바꾸려면 배열 전체를 새로 만들어야 한다. 1개의 요소만 바꾸면 되는데 바꾸지 않아도 되는 요소를 포함해서 바꿔야 되기에 시간이 오래 걸리게 되고, 그 결과 객체가 크고 복잡할 수록 효율이 떨어질 수 밖에 없다.


참고

0개의 댓글