Posts 함수형 프로그래밍
Post
Cancel

함수형 프로그래밍

부수 효과가 없는 순수함수를 1급 객체로 간주하여 파라미터로 넘기거나 반환값으로 사용하는 것을 가능하도록 하여, 참조 투명성을 지키도록 하는 프로그래밍 패러다임

순수 함수형 프로그래밍만으로 개발을 하기에는 무리가 있다. 따라서 적절히 조절해가면서 개발을 해나가자.

요약

함수형 프로그래밍의 가장 큰 특징 두 가지

  • immutable data
  • first class citizen으로서의 function

immutable data

각 함수는 외부의 값을 변경하지 않고, side effect를 일으키지 않도록 하는 순수함수여야함.

first-class citizen

함수형 프로그래밍 패러다임에서는 함수일급객체로 간주됨. 일급객체(first-class citizen) 로서의 함수는 다음과 같은 특징을 가지고 있음

  • 변수나 데이터 구조 안에 함수를 담을 수 있어서, 함수의 파라미터로 전달할 수 있고, 함수의 반환값으로 사용할 수 있다.
  • 할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.
  • 함수를 리터럴로 바로 정의할 수 있다.

좀 더 자세히

함수형 프로그래밍에 대한 이해

프로그래밍 패러다임

근래의 프로그래밍 패러다임은 크게 아래와 같이 구분할 수 있다.

  • 명령형 프로그래밍 : 어떻게 할 건지(how)를 설명하는 방식
    • 절차지향 : 수행되어야할 순차적인 처리과정을 포함하는 방식
    • 객체지향 : 객체들의 집합으로 프로그램의 상호작용을 표현
  • 선언형 프로그래밍 : 무엇을 할건지(what)를 설명하는 방식
    • 함수형 프로그래밍 : 순수함수를 조합하여 소프트웨어를 만드는 방식
    • 반응형 프로그래밍 : 모든 데이터를 스트림으로 보고, 이를 구독하는 곳에서 변화에 따라 알아서 처리하는 프로그램을 말한다. 이벤트 위주의 로직을 조합가능한 모듈로 코딩하는 방법
      • 이때 함수형 프로그래밍 패러다임을 차용하여 함수형 반응형 프로그래밍으로 개발을 할 수도 있다.

함수형 프로그래밍의 등장

명령형 프로그래밍을 기반으로 개발하던 소프트웨어는, 규모가 커짐에 따라 복잡하게 엉킨 스파게티 코드가 되어 유지보수에 매우 힘들었다. 이를 해결하기 위해 함수형 프로그래밍이라는 패러다임이 등장하여 주목을 받았다. 함수형 프로그래밍은 거의 모든 것을 순수함수로 나누어 문제를 해결하는 기법으로 작은 문제를 해결하기 위한 함수를 작성하여 가독성을 높이고 유지보수를 용이하게 해준다.

함수형 프로그래밍에 대한 이해

클린코드의 저자는 함수형 프로그래밍을 대입문이 없는 프로그래밍이라고 정의하였다.

함수형 프로그래밍은 대입문을 사용하지 않는 프로그래밍이며, 작은 문제를 해결하기 위한 함수를 작성한다.

예시

1
process(10, print(num));

process 함수는 첫번째 인자로 몇까지 iteration을 돌 것인가를 받고, 두번째 인자로는 전달받은 값을 출력하라는 함수를 매개변수로 받고 있다.

함수형 프로그래밍은 무엇을에 포커스를 두는 프로그래밍이고, 따라서 함수형 프로그래밍에서는 출력을 하는 함수를 파라미터로 넘길 수 있고, 이는 함수형 프로그래밍의 기본 원리 중 First-class Citizen이 보장되기에 가능한 방법이다.

명령형 프로그래밍에서는 메소드를 호출하면 상황에 따라 내부의 값이 바뀔 수 있다. 즉, 우리가 개발한 함수 내에서 선언된 변수의 메모리에 할당된 값이 바뀌는 등의 변화가 발생할 수 있다.

하지만 함수형 프로그래밍에서는 대입문이 없기 때문에 메모리에 한번 할당된 값은 새로운 값으로 변화할 수 없다.

함수형 프로그래밍의 특징

부수 효과가 없는 순수함수를 1급 객체로 간주하여 파라미터로 넘기거나 반환값으로 사용할 수 있으며, 참조 투명성을 지킬 수 있다.

여기서 부수효과(side effect)는 다음과 같다.

  • 변수의 값이 변경됨.
  • 자료 구조를 제자리에서 수정함
  • 객체의 필드값을 설정함
  • 예외나 오류가 발생하며 실행이 중단됨
  • 콘솔 또는 파일 I/O가 발생함

이러한 부수효과들을 제거한 함수들을 순수함수라고 부르며, 함수형 프로그래밍에서 사용하는 함수는 이러한 순수함수들이다.

  • Memory or I/O 관점에서 side Effect가 없는 함수
  • 함수의 실행이 외부에 영향을 끼치지 않는 함수(파라미터 + 자기 내부의 값만 사용)

순수함수를 이용하면 얻는 장점들

  • 함수 자체가 독립적이며 side-effect가 없기 때문에 thread에 안정성을 보장받을 수 있다. 따라서 병렬처리를 동기화 없이 진행할 수 있다.
  • 부수효과가 없기에 신뢰성있게 어디서든 쓸 수 있다.

참조투명성 (Referential Transparency)

  • 동일한 인자에 대해 항상 동일한 결과를 반환해야한다.
  • 참조 투명성을 통해 기존의 값은 변경되지 않고 유지된다.

명령형 프로그래밍과 함수형 프로그래밍에서 사용되는 함수는 부수효과의 유무에 따라 차이가 있다. 그에따라 함수가 참조에 투명한지 안한지 나뉘어진다.

참조에 투명하다는 것은 같은 값에 항상 동일한 결과를 반환하여 실행결과를 참조(예측)할 수 있다는 말이다. 이렇게 부작용을 제거하여 프로그램의 동작을 이해하고 예측을 용이하게 하는 것이 함수형 프로그래밍으로 개발하려는 핵심 동기이다.

또, 함수형 프로그래밍에서는 값의 대입이 없어 항상 동일한 실행에 동일한 결과를 반환하기 때문에, 병령처리 환경에서 Race condition에 대한 비용을 줄어준다.

순수함수의 예시

  • 순수함수
1
2
3
4
5
6
7
function countAdd(val1, val2) {
  return val1 + val2;
}
console.log(countAdd(5, 10)); // result - 15
console.log(countAdd(5, 10)); // result - 15
console.log(countAdd(5, 10)); // result - 15
console.log(countAdd(10, 20)); // result - 30
  • 비 순수함수
var number = 1;
function countAdd2(val1, val2) {
    return val1 + val2 + number;
}
console.log(countAdd2(5, 10)); // result - 16
number = 10;
console.log(countAdd2(5, 10)); // result - 25
var number = 1;
function countAdd3(val1, val2) {
    number = val1 + val2;
    return val1 + val2 + number;
}
console.log(countAdd3(5, 10));
  • 리액트에서의 순수함수 : 함수형 컴포넌트의 구현
    • 모든 React 컴포넌트는 자신의 props을 변경하지 않고, 자신의 내부에 있는 상태들만을 변경해야함.
    • 따라서 props를 변화시켜야하는 상황이 발생할 경우에는, props의 값을 state로 복사하여 그 state를 변화시키는 방식으로 동작함.

함수형 프로그래밍을 위한 자바스크립트 패턴

자바스크립트는 함수형 프로그래밍을 위해 좋은 언어지만, 멀티 프로그래밍 패러다임 언어이기에, 함수형 프로그래밍으로 작성하려면 항상 신경을 써야한다.

let보다 가급적 const를 사용해라

1
2
3
4
5
6
7
8
9
10
// bad
let foo = 100
...
foo = somthing(foo, "bar")


// good
const foo = 100
...
const new_foo = somthing(foo, "bar")

Array, Date에서 원본을 변형하는 메서드는 가급적 사용하지 마라

push, pop, shift, sort, reverse 등 원본을 mutate하는 method 대신 가급적 spread operator 로 대체하거나 값을 복사해서 사용하라

1
2
3
4
5
6
7
8
9
10
11
12
13
// bad
const example = (arr: number[], date: Date) => {
  arr.push(4);
  arr.sort();
  date.setMonth(10);
};
// good
const example = (arr: number[], date: Date) => {
  const new_arr = [...arr, 4];
  const sorted_new_arr = [...new_arr].sort();
  const new_date = new Date(date).setMonth(10);
  return [new_arr, new_date];
};

가급적 Object의 필드에 대입연산자를 쓰지 마라

1
2
3
4
5
6
7
8
// bad
const example = (obj: Object) => {
  obj.foo = 200;
};
// good
const example = (obj: Object) => {
  return { ...obj, foo: 200 };
};

가급적이라는 표현대로, 극단적으로 지키기보단, 요구사항을 위해 어쩔 수 없다면 어길 수 밖에 없다. 이에 집착하지 마라. 좋은 점을 잘 골라서 취합

함수형 반응형 프로그래밍(WIP)

Functional Reactive Programming

반응형 프로그래밍을 달성하기 위해, 함수형 프로그래밍 규칙을 강제하는 방법이다.

실제 개발을 하다보면, 순수 함수형으로 개발하는 것은 불가능에 가깝다. 따라서 반응형 프로그래밍과 결합하여 프로그래밍을 할 수 있다.

리액트로 예를들면, 사용자가 입력을 하면 그것을 처리하여 외부의 상태를 업데이트하는 함수가 존재하고, 그 상태에 반응하여 호출되는 함수들이 존재한다.

출처

https://mangkyu.tistory.com/111

https://gyuwon.github.io/blog/2020/07/24/react-has-no-functional-components.html

https://velog.io/@teo/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%9D%BC%EB%8B%A8-%ED%95%9C%EB%B2%88-%ED%95%B4%EB%B3%B4%EC%84%B8%EC%9A%94-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D

This post is licensed under CC BY 4.0 by the author.

알고리즘 팁(WIP)

9935 문자열 폭발

Comments powered by Disqus.