함수형 프로그래밍이란

함수형 프로그래밍은 순수함수, 수학적인 함수를 사용하는 프로그래밍입니다.

인터넷 검색을 통해서 아마 다음과 같은 정의를 볼 수 있습니다:

(순수) 함수란 같은 입력에 항상 같은 결과를 내는 부작용없는 절차입니다.

여기서 "부작용" 이란 용어의 정의를 설명하지 않았지만 (이후 공식적인 정의를 보게될것입이다) 직관적으로 파일을 열거나 데이터베이스의 쓰기같은 것을 생각해볼 수 있습니다.

지금 당장은 부작용이란 함수가 값을 반환하는 작업 이외에 하는 모든것이라고 생각하시면 됩니다.

순수함수만 사용하는 프로그램은 어떤 구조를 가질까요?

보통 함수형 프로그램은 pipeline 형태로 이루어져 있습니다.

const program = pipe(
  input,
  f1, // 순수 함수
  f2, // 순수 함수
  f3, // 순수 함수
  ...
)

여기서 input은 첫 번째 함수인 f1으로 전달되고 그 결과는 두 번째 함수인 f2로 전달됩니다.

이어서 f2가 반환하는 값은 세 번째 함수인 f3로 전달되고 이후 같은 방식으로 진행됩니다.

데모

00_pipe_and_flow.ts

앞으로 함수형 프로그래밍이 위와 같은 구조를 만들어주는 도구를 제공하는지 보게될 것입니다.

함수형 프로그래밍이 무엇인지 이해하는 것 외에 이것의 궁극적인 목적을 이해하는 것 또한 중요합니다.

함수형 프로그래밍의 목적은 수학적인 모델 을 사용해 시스템의 복잡성을 조정하고 코드의 속성 과 리팩토링의 편의성에 중점을 두는 것입니다.

(원문) Functional programming's goal is to tame a system's complexity through the use of formal models, and to give careful attention to code's properties and refactoring ease.

함수형 프로그래밍은 프로그램 구조에 감춰진 수학을 사람들에게 가르치는 것에 도와줍니다:

  • 합성 가능한 코드를 작성하는법
  • 부작용을 어떻게 다루는지
  • 일관적이고 범용적이며 체계적인 API 를 만드는 법

코드의 속성에 중점을 둔다는 것이 무엇일까요? 예제를 살펴보겠습니다:

예제

for반복문보다 Arraymap이 더 함수형이라고 할까요?

// 입력
const xs: Array<number> = [1, 2, 3]

// 수정
const double = (n: number): number => n * 2

// 결과: `xs` 의 각 요소들이 2배가 된 배열을 얻고싶다
const ys: Array<number> = []
for (let i = 0; i <= xs.length; i++) {
  ys.push(double(xs[i]))
}

for반복문은 많은 유연성을 제공합니다. 즉 다음 값들을 수정할 수 있습니다.

  • 시작 위치, let i = 0
  • 반복 조건, i < xs.length
  • 반복 제어, i++.

이는 에러를 만들어 낼 수 있음을 의미하며 따라서 결과물에 대한 확신이 줄어듭니다.

문제. 위 for 반복문은 올바른가요?

위 예제를 map을 활용해 작성해봅시다.

// 입력
const xs: Array<number> = [1, 2, 3]

// 수정
const double = (n: number): number => n * 2

// 결과: `xs` 의 각 요소들이 2배가 된 배열을 얻고싶다
const ys: Array<number> = xs.map(double)

mapfor 반복문에 비해 유연성이 적지만 다음과 같은 확신을 제공합니다.

  • 입력 배열의 모든 요소에 대해 처리될것이다.
  • 결과 배열의 크기는 입력 배열의 크기와 동일할 것이다.

함수형 프로그래밍에선 구체적인 구현보다 코드의 속성에 더 집중합니다.

map 연산의 제약사항이 오히려 유용하게 해줍니다.

for 반복문 보다 map 을 사용한 PR 을 리뷰할 때 얼마나 편한지 생각해보세요.