SICP JS - 1.3: 고차 함수로 추상화를 공식화하기
2023. 12. 13.
SICP JS를 읽고, 이미 체득했다고 생각하는 정보들은 제외한 후 기억해둘 만하다 생각한 정보를 나열(정리가 아니다!)하였다.
공통된 패턴에 이름을 붙여주어 추상화하고, 이렇게 구축된 추상화의 관점에서 직접 작업할 수 있어야 한다. ‘함수’가 이러한 능력을 제공한다. 그러나 함수의 입력을 오직 수만 받을 수 있게 제한한다면 추상화를 만들 수 있는 능력에도 제한이 있을 것이다. 비슷한 패턴이 여러 다른 함수들에도 적용되는 경우가 많으며, 이런 패턴을 표현하기 위해서는 다른 함수의 입력값이나 출력값으로 받아들여질 수 있는 함수를 만들 수 있어야 하며, 이러한 함수를 **고차 함수(higher-order function)**이라고 한다.
예를 들어 정수 부터 까지 각각의 합을 구하는 함수 , 제곱의 합을 구하는 함수 , 세제곱의 합을 구하는 함수 등등을 생각해보자. 연산에 사용되는 수는 각각 , , 으로 다르지만 ‘합’을 구한다는 점에서는 모두가 동일하기 때문에, 수학자들은 (시그마) 기호를 통해 ‘무언가의 합을 구하는 과정‘을 추상화해냈다. 따라서 우리는 이 추상화를 이용하여, 각 함수를 다음과 같이 표현할 수 있다.
이러한 추상화를 프로그래밍에도 마찬가지로 적용할 수 있다.
// term, next는 함수
function sum(term, a, next, b) {
return a > b ? 0 : term(a) + sum(term, next(a), next, b);
}
이렇게 만들어진 sum
함수는 더 복잡한 수치의 합을 계산하기 위한 기본 요소로 사용할 수 있다.
이 때, term
과 next
같이 한 번에 더해질 값을 계산하는 함수나 다음 번에 사용될 수를 계산하는 함수의 경우, 그 형태가 매우 간단하여 굳이 이름을 붙여 추상화 단위를 만들 필요가 없을 수도 있다. 람다 표현식(lambda expression)을 사용하면 함수에 별도로 이름을 붙이지 않을 수 있다(즉, ‘익명 함수’를 만들 수 있다). 물론, 별도의 지역 변수를 선언하여, 해당 변수명으로 함수에 접근할 수도 있다.
1.1에서 복합 연산에 이름을 붙여 하나의 단위로 다루기 위해 ‘함수’를 사용한다고 말한 바 있다. 이 때 함수는 매개변수(parameter)를 사용하여 해당 연산의 형태를 추상화해내며, 이는 곧 해당 연산이 특정한 값에 묶여있지 않고 연산이 이루어지는 패턴 그 자체를 독립적으로 표현할 수 있도록 한다(대체 뭔 소리지).
이와 마찬가지로, 우리는 고차 함수를 통해 좀 더 강력한 종류의 추상화를 할 수 있다. 한 문장으로 정리해보자면, 어떠한 ‘계산(computation)’을 일반적으로(즉, 특정한 함수 표현에 묶이지 않고) 표현하기 위해 고차 함수를 사용한다고 할 수 있다(진짜로 무슨 소리지…).
함수를 입력으로 제공하는 것과 마찬가지로, 어떠한 함수의 결과값을 함수 형태로 제공할 수 있으면 프로그래밍 언어의 표현력을 더욱 향상시킬 수 있다. 똑같은 절차를 수행하는 함수라고 하더라도, **‘올바른 형태의 추상화 단위’**로 표현해야 더 명확하게 핵심 아이디어를 알아볼 수 있다는 점을 인지할 것. 숙련된 프로그래머는 어떤 형태의 조합이 더 명쾌하게 보일지, 또 작업이 어떠한 단위로 나뉘어야 다른 곳에서 응용할 때 유용하게 사용될 지를 알고 있다.
일반적으로, 프로그래밍 언어는 자신이 다룰 수 있는 요소를 조작하는 방법에 대해 제약을 둔다. 이러한 제약이 가장 적은 요소는 ‘일급’(first-class) 요소라고 부르며, 이러한 일급 요소들은 이름으로 접근할 수 있고, 함수의 입력 또는 출력으로 제공될 수 있으며, 자료구조에 포함될 수 있는 ‘권리’를 가진다.
- SICP, SICP JS, 컴퓨터 프로그램의 구조와 해석