BlogApplicationsGuestbook

Github | X (Twitter)

Copyright © 2024 OPNay - All Reserved | Privacy Policy

함수형 프로그래밍 알아보기

2023.08.28 03:47

x

자바스크립트는 객체지향 프로그래밍과 함수형 프로그래밍을 지원하는 멀티 패러다임 언어입니다. 이로 인해 prototype, class를 통한 객체지향의 코드가 만들어지기도 하며, encodeURIComponent, Math.max 같이 함수형 프로그래밍의 코드가 만들어지기도 합니다. 이 두가지 모두 현재까지 사용되는 패러다임이며, 실제로 두가지를 혼용해가며 사용할 때도 있습니다. 그렇기 때문에 코드를 보다보면 어떤게 함수형이고, 어떤게 객체지향인지 혼동될 때도 있으니 이 두가지를 잘 알아두어야 합니다. 이번 글에서는 많이 알려진 객체지향 보다는 다소 생소한 함수형 프로그래밍을 정리해보려합니다.

함수형 프로그래밍

함수형 프로그래밍은 선언형 프로그래밍의 한 갈래입니다. 따라서 상태를 바꾸는 형태인 명령형과는 다르게 식과 선언으로 이루어진 선언형의 특징을 띄고 있습니다. 그리고 함수형은 다음과 같은 특징이 더 있습니다.

  • 함수를 변수 처럼 다룰 수 있도록 1급 객체로 취급해야한다.
  • 함수는 순수 함수가 되어야 한다.
  • 대입을 하지 않는다. (불변의 값을 사용한다)
    이러한 특징들을 지키며 만들다 보면, 변수를 쉽게 예측할 수 있고, 함수의 이름으로만 그 기능을 확실히 알 수 있다는 장점이 있어요. 그럼에 따라 함수를 읽을 때 좀더 빠르게 이해할 수 있는 쉬운 코드 모양이 나타나게 되는거죠.

함수는 1급 객체 (First-class citizens)

1급 객체(First-class citizens)라는 말을 처음 들어 보실 겁니다. 변수에 저장하고, 함수의 매개 변수나 반환 값으로서 사용할 수 있는 Entity를 이야기 합니다.

어려운 말일지 모르겠지만, 여러분이 자주 사용하던 Array.prototype.map, Array.prototype.sort처럼 매개 변수로 함수를 받고, React의 useCallback 처럼 함수를 반환하고, 변수에 저장하는 것을 의미합니다.

const arr = [1, 2, 3, 4]; const increased = arr.map((it) => it + 1); // 함수를 매개변수로 사용 // 화살표 함수를 App이라는 변수에 함수를 저장 const App = () => { // 함수를 반환하고, 변수에 저장할 수 있는 특징 const click = useCallback(() => console.log('clicked!'), []); return <button onClick={click}>버튼</button> };
javascript

1급 객체 예제

순수 함수

기본적으로 함수는 입력받은 값을 통해 기능을 수행한 후, 결과를 반환하는 것을 이야기합니다. 이러한 단일 목적을 가지는 함수를 “순수 함수”라고 부릅니다. 그러나 주된 목적이 존재하나, 별도의 다른 목적을 가지는 함수 또한 만들어 질 수 있습니다. 다른 목적을 나타내는 것을 “부수 효과(Side Effect)”라고 부릅니다. 간단하게 이야기하면, “함수를 동작했는데 왜 다른게 바뀌는 거지?”를 프로그래밍 용어로 표현한 겁니다. 이런 부수 효과를 가지고 있는 함수를 “불순 함수”라고도 합니다.

let value = 0; function increase(amount) { value += amount; // Side Effect! return value; }
javascript

불순 함수 에제

위 예제에서는 increase 라는 함수는 “주어진 값 만큼 증가한다”라는 주된 목적을 가집니다. 하지만, 주어진 매개 변수 이외의 value 라는 외부 상태를 통해 값을 다루고 있어, “주어진 값 만큼 증가한다” 라는 목적 외의 “외부 상태의 value 를 저장한다”라는 별도의 목적을 가지고 있습니다. 이 때문에 부수 효과를 가진 함수로서 이 함수는 불순 함수로 정의 할 수 있습니다. 이 문제를 순수 함수로 재작성 하면 다음과 같습니다.

function increase(base, amount) { return base + amount; } console.assert(increase(0, 10) === 10); // 예측 가능함.
javascript

순수 함수로 재작성

앞서 말한 “주어진 값 만큼 증가한다”에 집중된 함수의 순수한 기능입니다. 기존의 value 라는 외부 상태를 base 라는 매개 변수로 바꾸면서, “외부 상태에 저장한다”라는 목적을 제거해 단일 목적으로 함수를 재작성 했습니다. 이로써 increase 는 순수 함수가 되었습니다.

이 처럼 외부 상태에 의존해 사용하는 함수는 여러분이 사용하는 자바스크립트에도 많이 존재합니다. 그 중에서도 Array.prototype.push, Array.prototype.sort 와 같이 배열 값 자체를 바꾸려는 함수(사실 이 두개의 함수는 프로토타입 객체지향입니다)가 존재하며, fetch, window.matchMedia, document.getElementById 같이 네트워크나 브라우저 DOM이라는 외부 상태를 이용한 함수들이 존재합니다. 이러한 함수들 때문에 자바스크립트에서는 100% 완벽한 함수형 프로그래밍을 하지 못한다는 것을 아셔야합니다.

function addNext(number_array) { const [last] = number_array.slice(-1); // 마지막 값을 가져온다. // 매개 변수를 수정하므로, 매개 변수 자체가 외부 상태로서 부수 효과가 된다. number_array.push(last + 1); } function isDarkMode() { // `window` 라는 객체의 상태를 이용하기 때문에 이 또한 부수 효과입니다. const { matches } = window.matchMedia('(prefers-color-scheme: dark)'); return matches; } function addTitle(title) { const header = document.createElement('h1'); header.innerText = title; // `body` DOM을 수정하는 행위이기 때문에 이 또한 부수 효과가 됩니다. document.body.appendChild(header); } async function fetchPosts() { // 네트워크라는 외부 상태를 이용한다. const response = await fetch('.../api/posts'); return response.json(); }
javascript

자바스크립트의 불순 함수

순수 함수는 부수 효과가 존재하지 않기 때문에 스레드 안정성을 보장할 수 있습니다. 또한, 테스트 케이스 작성에 더 용이하다는 장점이 있습니다.

대입을 하지 않는다. (불변의 값을 사용한다)

함수형 프로그래밍에서 변수는 바뀌면 안됩니다. 객체의 속성과 배열의 요소까지도요. 값을 변경하는 건 상태를 다루는 것이고, 당연히도 순수 함수를 다루는 함수형 프로그래밍에서는 나타나선 안되는 패턴이기도 합니다. 그리고 상태를 바꾸는건 당연히 선언형 프로그래밍이 아닌 명령형 프로그래밍을 의미하게 됩니다. 이 때문에 변수 선언 방식이 가변의 let 보다는 불변 선언인 const 선언을 주로 사용하고, for, while, continue 같이 흐름 제어 보다는 Array.prototype.map, Array.prototype.forEach 같은 함수형태의 흐름제어를 주로 사용하게 됩니다.

// 배열에서의 불변 const arr = [1, 2, 3, 4]; const increased = arr.map((it) => it + 1); function SomeComponent() { const [state, setState] = useState(0); // state 값을 직접 증가하지 않고, setState 함수를 통해 값을 증가 const increase = () => setState((prev) => prev + 1); return ( <div> <span>{state}</span> <button onClick={increase}>Increase Button</button> </div> ); }
javascript

자바스크립트 진영에서 개발을 해오면서 어렴풋이 사용하던 함수형 프로그래밍을 정리했습니다. 현재도 자바스크립트는 계속 객체지향과 함수형을 병행하며 사용되고, 이로인해 코드의 규칙을 잡기 어려울 때가 있습니다. 이번 정리를 통해 좀더 함수형 프로그래밍을 개발할 때는 제대로된 규칙을 갖고 개발했으면 좋겠습니다.

참조

 

함수형 프로그래밍 알아보기

    [프로그래밍] 함수형 프로그래밍(Functional Programming) 이란?

    1. 함수형 프로그래밍(Functional Programming)에 대한 이해 [ 프로그래밍 패러다임(Programming Paradigm) ] 프로그래밍 패러다임(Programming Paradigm)은 프로그래머에게 프로그래밍의 관점을 갖게 하고 코드를 어떻게 작성할 지 결정하는 역할을 한다. 새로운 프로그래밍 패러다임을 통해서는 새로운 방식으로 생각하는 법을 배우게 되고, 이를 바탕으로 코드를 작성하게 된다. 최근의 프로그래밍 패러다임은 크게 아래와 같이 구분할 수 있다. 명령형 프로그래밍: 무엇(What)을 할 것인지 나타내기보다 어떻게(How) 할 건지를 설명하는 방식 절차지향 프로그래밍: 수행되어야 할 순차적인 처리 과정을 포함하는 방식 (C, C++) 객체지향 프로그래밍: 객체들의 집합으로 ..

    [프로그래밍] 함수형 프로그래밍(Functional Programming) 이란?https://mangkyu.tistory.com/111

    [프로그래밍] 함수형 프로그래밍(Functional Programming) 이란?

    Functional Programming For Your Everyday JavaScript Developer | by Travis Waith-Mair | Non-Traditional Dev | Medium

    JavaScript has a pretty diverse set of developers. One of the biggest reasons is that JavaScript supports multiple programming paradigms. JavaScript can be written imperatively, you can use an…

    Functional Programming For Your Everyday JavaScript Developer | by Travis Waith-Mair | Non-Traditional Dev | Mediumhttps://medium.com/the-non-traditional-developer/functional-programing-for-your-everyday-javascript-developer-f5efad54397d

    Functional Programming For Your Everyday JavaScript Developer | by Travis Waith-Mair | Non-Traditional Dev | Medium