Sleeep23' space
Front-end Engineer

자바스크립트로 배우는 SICP - 2. 추상화, 추상화, 추상화...

이름, 함수로의 추상화와 복합 연산 및 함수의 평가 방식에 대해서 알아보자

2023-10-24 | 독서 | 8min


sicpjs-1 thumbnail

존 로크의 추상화

존 로그의 인간지성론에서는 추상화를 다음과 같이 정의하고 있다.

  1. 다수의 단순 관념을 하나의 복합(compound) 관념으로 조합한다. 이를 통해 복잡한 관념들이 만들어진다.
  2. 둘째는 두 관념을 가져와 또 다른 관념으로 설정함으로써 그 둘을 하나의 관념으로 통합하지 않고도 두 관념을 한 번에 볼 수 있게 만드는 것이다.
  3. 하나의 관념을 그 실제 존재에 수반하는 다른 모든 관념으로부터 분리하는 것이다.

위는 1장 첫 페이지에 인용된 문을 요약한 것이다. 어떻게 보면, 앞으로 다를 추상화 라는 개념에 대해서 명쾌하게 설명하고 있다고 생각한다. 이를 곱씹어보며 이후의 내용을 보자.

계산적 과정 그리고 자바스크립트

다음으로 나오는 내용은 계산적 과정이다. 계산적 과정의 정의는 다음과 같다.

계산적 과정은 어떤 구체적인 산술 계산을 수행하는 과정보다는 좀 더 넓은 개념으로 “그 과정의 세부절차 단계들을 명확히 규정할 수 있으며 형식화할 수 있”는 과정을 말한다 (옮긴이의 말)

이러한 계산적 과정은 컴퓨터 내에서 살아가는 추상적인 존재이다. 이 과정이 전개되면서 데이터 라는 존재를 조작하게 된다. 그리고 이 들의 과정은 일정한 규칙들의 패턴에 따라 전개되는데 이것이 프로그램 이다.

이처럼 계산적 과정의 세부절차를 서술하기 위해서는 언어가 필요하다. 이것이 프로그래밍 언어이며 책에서는 자바스크립트를 이용하고 있다.

본질적으로 프로그래머는 자신의 주문들로 컴퓨터의 영혼을 불러낸다

이전에도 언급했지만 이 부분이 내가 개발을 좋아하는 이유가 아닐까 싶다. 단순히 가지고 있는 생각을 현실화 할 수 있다는 점 자체가 너무나 매력적인 부분이다. 내가 만들고 싶은 것들에 대한 세부 절차들이 명확히 규정되어 있다면, 프로그래밍 언어에 대한 지식으로 만들 수 있는 것이 되어버리기 때문이다. 근데 이렇게 보니 뭔가 호그와트 갔으면 재밌게 마법도 배웠을 것 같다.

프로그래밍의 기본요소

프로그래밍은 우리가 과정에 대한 생각들을 조직화하는 틀로도 작용한다. 그래서 단순한 아이디어들을 조합해서 복잡한 아이디어를 만들기 위해 모든 강력한 언어들은 다음과 같은 세 가지 기능을 제공한다

  • 원시 표현식 : 언어와 관련된 가장 단순한 개체(entity)를 나타낸다.
  • 조합 수단 : 단순한 요소들로부터 복합적인 요소를 만드는 데 쓰인다.
  • 추상화 수단 : 복합적인 요소들에 이름을 붙여서 하나의 단위로 다루는 데 쓰인다.

위 부분은 존 로크의 추상화와 잘 맞아떨어진다. 원시 표현식은 존 로크의 추상화에서 단순 관념 을 의미하는 것 같았다. 그리고 이러한 단순 관념의 조합으로 만들어는 복합 관념 이 바로 언어들의 조합 수단을 통해 만들어지는 복합적인 요소들이 되며 이에 이름을 붙이는 것이 분리의 과정 에 속하는 것이라고 생각해보았다.

이렇게 인간지성의 추상화 개념을 프로그래밍 언어에 적용한 이유를 생각해보니, 애초에 프로그래밍 언어는 컴퓨터와 소통도 되지만 이를 사용하는 주체는 인간이다. 그리고 개발자는 프로그래밍 언어를 통해 컴퓨터와 소통도 하지만, 다른 인간과 상호작용을 한다. 이 과정에서 각자의 추상화가 공통적으로 잘 받아들여지기 위해서는 인간과 컴퓨터 모두가 받아들이기에 편한 방법을 제시해야기에 이러한 방법을 이용하지 않나 싶다.

가장 간단한 추상화 수단 - 이름 붙이기

복잡한 구조의 세부사항을 기억해두고 객체 사용 시마다 그 구조를 거듭 명시하는 것은 극히 불편한 일이다. 가장 간단한 추상화 수단은 바로 이름 붙이기 다. 변수를 설정한다는 것이다. 책에서는 이름 붙이기에 대하여 아래와 같이 소개하고 있다.

이름 붙이기는 계산적 객체에 이름을 붙어서 객체를 지칭하는 수단이다. 이는 가장 단순한 추상화 수단이다.

  • 자바스크립트의 const 키워드는 이름을 상수로 선언하는 것이다.
  • 이름을 붙이는 것은 해석기를 통해 이름과 객체간의 연관관계를 조성해나가는 것이다.

위와 같이 어떠한 값이나 객체를 반복적으로 이용하지 않기 위해 추상화한 이름 붙이기 수단은 연산자 조합의 평가에서도 쓰인다.

연산자 조합의 평가

연산자 간 조합을 평가하기 위한 방식은 다음과 같이 크게 두 과정으로 나뉜다.

  1. 조합의 피연산자 표현식들을 평가한다
  2. 연산자가 나타내는 함수를 인수(피연산자들의 값)들에 적용한다.

그리고 위 과정이 재귀적으로 이루어진다.

우선 주어진 복합 연산자 조합을 연산자와 피연산자로 나누어 트리구조로 시각화한다. 그리고 해당 잎사귀 노드(말단 노드)에서 출발해서 피연산자들의 값을 해당 연산자에 따라 결합하여 값을 위로 올려보내는 트리 누산 의 과정으로 평가가 진행된다. (참고로, 변수의 선언은 이름에 값을 연관시키는 작업이지 연산자 평가가 이루어지지는 않는다.)

이 과정 속에서 원시 표현식(수치나 이름)을 평가해야 하는 지점에서 수치는 그 값 자체로, 이름의 값은 이름에 연관된 객체로 평가된다.

내가 보기에 위 내용은 컴파일러 내부의 구문 분석(syntax analysis) 과정에서 진행되는 파싱(parsing) 과정의 일부와 원시 표현식의 경우 symbol table에 등록되어 해당 심볼들이나 수치의 값을 이용하여 평가가 진행된다는 것을 소개하고 있는 듯이 보였다.

아무래도 자바스크립트는 interpreter 언어라 컴파일 과정과 실행과정이 분리되어 진행되지 않기에 내가 앞서 언급한 그대로로 진행될 것 같지는 않았다. 이 부분에 대해서는 크롬의 자바스크립트 해석기인 v8엔진의 내부 구조를 들여다봐야 알 수 있을 것 같았다. 나중에 시간이 되면 공부한 포스팅을 올려봐야겠다.

지금까지는 변수로의 추상화와 연산자 평가 단계에서 활용되는 방식이 어떻게 이루어지는지 보았다.

강력한 추상화 기법 - 함수 선언

이제는 함수의 선언이다. 단순한 수치에 이름을 붙이는 것이 아닌 복합 연산에 이름을 붙여서 해당 연산을 하나의 단위로 지칭하게 하는 것이다. 이는 상수 선언보다 훨씬 강력한 추상화 기법이다.

다음 함수를 보자.

function square(x) {
	return x * x
}

위는 일상의 용어와 연관지을때 다음과 같이 매핑된다.

//   To    square  something  , 	     take it  times  itself
	function square (    x    )  { return   x       *       x   }
 

여담이지만, 위를 보니 뭔가 함수를 어떻게 명명해야 될 지에 대한 감을 잡은 느낌이다. 지금까지는 단순하게 이름을 규칙없이 붙여왔는데 일상의 용어와 연관지으면서 이름을 짓는다면 코드를 읽는 사람도, 나도 이해하기 쉽게 추상화된 함수를 사용할 수 있겠다는 생각이 들었다.

함수에서 중요한 점은 이름의 선언과 복합 연산의 평가가 같이 한데 묶여있는 것이다. 즉, 1. 함수 자체를 생성하는 것2. 해당 함수에 square 이라는 이름을 붙이는 것이다. 즉, 함수의 이름은 함수의 정의와 연관시킬 기호라는 것이다.

함수의 평가 - 함수 적용의 치환모형

이어서 함수가 어떻게 평가되는지를 소개하고 있다.

이는 크게 인수 우선 평가(또는 적용적 순서 평가)와 정상 순서 평가(또는 표준 순서 평가)로 나뉜다.

인수 우선 평가

두 매개변수를 받아 각각의 제곱을 더하는 함수인 sum_of_squares 가 있다고 하자. 이는 인수 우선 평가에서는 다음과 같이 평가된다.

f(5) // 5 라는 값에 함수 f를 적용시켰다. f의 반환 표현식은 다음과 같다.
sum_of_squares(a + 1, a * 2)

위 함수는 다음과 같이 평가된다.

sum_of_squares(5 + 1, 5 * 2) // 참고로 sum_of_squares는 위에서 작성한 square 함수의 합으로 구현된다.
--> sum_of_squares(6, 10)
--> square(6) + square(10)
--> (6 * 6) + (10 * 10)
--> 36 + 100
--> 136

이렇게 인수의 평가가 그때 그때 우선적으로 진행된다. 이후 함수가 반환하는 표현식으로의 치환이 이루어진다.

정상 순서 평가

이는 아래와 같이 평가된다.

sum_of_squares(5 + 1, 5 * 2)
--> square(5 + 1) + square(5 * 2)
--> (5 + 1) * (5 + 1) + (5 * 2) * (5 * 2)
-->    6    *    6    +    10   *    10
-->        36         +         100
-->                  136

위는 우선 함수의 반환 표현식으로 완전히 전개한다. 즉, 연산자들과 원시 함수들만 관여하는 표현식을 평가할 때가 되면 비로소 그 인수 표현식들을 평가한다. 인수의 값이 실제로 필요해질 때까지 인수 표현식의 평가를 미루는 모형이다.

자바스크립트는 인수 우선 평가 방식 을 이용하는데 이는 정상 순서 평가에서 (5 + 1)이 두 번씩 나온 것 처럼 그 비효율성을 피하기 위함이기도 하며, 치환 모형 이외의 함수들에 대해서는 정상 순서 평가가 훨씬 복잡하다고 한다. (사실 이에 대해서는 직관적으로 다가오지는 않는다. 앞으로 다가올 3,4장에서도 소개한다고 하니 기다려봐야겠다.)

마무리

이렇게 이번 책너두 챌린지 범위 내용 중 인상깊은 부분들에 대한 소개 및 생각을 서술해보았다. 근데 쓰고 나보니 내용이 너무나 많다… 작성 시간도 너무 오래 걸린다… 아무래도 소개하는 부분을 줄여야 하나… 고민이다. 어찌됐든 오늘 하루도 알찬 내용을 알고 간다!