SICP JS - 1.3: 고차 함수로 추상화를 공식화하기

2023. 12. 13.


SICP JS를 읽고, 이미 체득했다고 생각하는 정보들은 제외한 후 기억해둘 만하다 생각한 정보를 나열(정리가 아니다!)하였다.

공통된 패턴에 이름을 붙여주어 추상화하고, 이렇게 구축된 추상화의 관점에서 직접 작업할 수 있어야 한다. ‘함수’가 이러한 능력을 제공한다. 그러나 함수의 입력을 오직 수만 받을 수 있게 제한한다면 추상화를 만들 수 있는 능력에도 제한이 있을 것이다. 비슷한 패턴이 여러 다른 함수들에도 적용되는 경우가 많으며, 이런 패턴을 표현하기 위해서는 다른 함수의 입력값이나 출력값으로 받아들여질 수 있는 함수를 만들 수 있어야 하며, 이러한 함수를 **고차 함수(higher-order function)**이라고 한다.

예를 들어 정수 aa부터 bb까지 각각의 합을 구하는 함수 F(a, b)F(a,\space b), 제곱의 합을 구하는 함수 G(a, b)G(a,\space b), 세제곱의 합을 구하는 함수 H(a, b)H(a,\space b) 등등을 생각해보자. 연산에 사용되는 수는 각각 ii, i2i^2, i3(iZ,aib)i^3(i \isin Z,a \le i \le b)으로 다르지만 ‘합’을 구한다는 점에서는 모두가 동일하기 때문에, 수학자들은 \sum(시그마) 기호를 통해 ‘무언가의 합을 구하는 과정‘을 추상화해냈다. 따라서 우리는 이 추상화를 이용하여, 각 함수를 다음과 같이 표현할 수 있다.

f(x)=x, g(x)=x2, h(x)=x3일 때,F(a, b)=aibf(i)=aibiG(a, b)=aibg(i)=aibi2H(a, b)=aibh(i)=aibi3f(x)=x,~g(x)=x^2,~h(x)=x^3일~때,\\F(a,~b)=\sum_{\substack{a\le i\le b}}{f(i)}=\sum_{\substack{a\le i\le b}}{i}\\G(a,~b)=\sum_{\substack{a\le i\le b}}{g(i)}=\sum_{\substack{a\le i\le b}}{i^2}\\H(a,~b)=\sum_{\substack{a\le i\le b}}{h(i)}=\sum_{\substack{a\le i\le b}}{i^3}

이러한 추상화를 프로그래밍에도 마찬가지로 적용할 수 있다.

// term, next는 함수
function sum(term, a, next, b) {
  return a > b ? 0 : term(a) + sum(term, next(a), next, b);
}

이렇게 만들어진 sum 함수는 더 복잡한 수치의 합을 계산하기 위한 기본 요소로 사용할 수 있다.

이 때, termnext같이 한 번에 더해질 값을 계산하는 함수나 다음 번에 사용될 수를 계산하는 함수의 경우, 그 형태가 매우 간단하여 굳이 이름을 붙여 추상화 단위를 만들 필요가 없을 수도 있다. 람다 표현식(lambda expression)을 사용하면 함수에 별도로 이름을 붙이지 않을 수 있다(즉, ‘익명 함수’를 만들 수 있다). 물론, 별도의 지역 변수를 선언하여, 해당 변수명으로 함수에 접근할 수도 있다.


1.1에서 복합 연산에 이름을 붙여 하나의 단위로 다루기 위해 ‘함수’를 사용한다고 말한 바 있다. 이 때 함수는 매개변수(parameter)를 사용하여 해당 연산의 형태를 추상화해내며, 이는 곧 해당 연산이 특정한 값에 묶여있지 않고 연산이 이루어지는 패턴 그 자체를 독립적으로 표현할 수 있도록 한다(대체 뭔 소리지).

이와 마찬가지로, 우리는 고차 함수를 통해 좀 더 강력한 종류의 추상화를 할 수 있다. 한 문장으로 정리해보자면, 어떠한 ‘계산(computation)’을 일반적으로(즉, 특정한 함수 표현에 묶이지 않고) 표현하기 위해 고차 함수를 사용한다고 할 수 있다(진짜로 무슨 소리지…).


함수를 입력으로 제공하는 것과 마찬가지로, 어떠한 함수의 결과값을 함수 형태로 제공할 수 있으면 프로그래밍 언어의 표현력을 더욱 향상시킬 수 있다. 똑같은 절차를 수행하는 함수라고 하더라도, **‘올바른 형태의 추상화 단위’**로 표현해야 더 명확하게 핵심 아이디어를 알아볼 수 있다는 점을 인지할 것. 숙련된 프로그래머는 어떤 형태의 조합이 더 명쾌하게 보일지, 또 작업이 어떠한 단위로 나뉘어야 다른 곳에서 응용할 때 유용하게 사용될 지를 알고 있다.

일반적으로, 프로그래밍 언어는 자신이 다룰 수 있는 요소를 조작하는 방법에 대해 제약을 둔다. 이러한 제약이 가장 적은 요소는 ‘일급’(first-class) 요소라고 부르며, 이러한 일급 요소들은 이름으로 접근할 수 있고, 함수의 입력 또는 출력으로 제공될 수 있으며, 자료구조에 포함될 수 있는 ‘권리’를 가진다.