프로그래밍언어는 일련의 과정에 관한 생각들을 조직화하는 틀로써 작용할 수 있다.
단순한 아이디어(or 매커니즘)들을 조합해서 복잡한 아이디어를 조직하는 것이다.
강력한 컴퓨팅 언어들은 다음 세가지 매커니즘을 제공한다.
- 원시 표현식(primitive expression) 수단
언어와 관련한 가장 단순한 객체 - 조합(combination) 수단
여러개의 단순한 요소들을 이용하여 복합적인 요소를 만듦 - 추상화(abstraction) 수단
복합적 요소에 이름을 붙여 하나의 단위로 다룸
표현식
표현식은 원시표현식, 연산자 조합으로 구성될 수있다.
- 원시 표현식
number, bigint, string, null, undefined, boolean, Symbol - 연산자 조합
피연산자 + 연산자 표현식 형태의 조합
이름 붙이기와 환경
- 변수선언
이름과 값을 연관시켜 변수 선언을 할 수 있는데, 이는 제한적이나마 추상화의 수단을 제공한다.
const 이름 = 표현식;
이름과 값을 연관시키고 조회할 수 있으러면, 해석기는 반드시 이름-객체 쌍을 저장하고 관리하는 메모리 공간을 갖추어야한다. 이를 환경(environment)이라고 한다.
- 함수선언
복합 연산에 이름을 붙여 그 연산을 하나의 단위로 지칭하는 것으로, 상수 선언보다 훨씬 강력한 추상화 기법이다.
function 이름(매개변수들) { return 표현식; }
함수 적용의 평가 절차는 다음과 같다.
- 함수 표현식과 인수 표현식들을 각각 평가한다.
- 함수 표현식의 값을 인수 표현식 값들에 적용한다.
연산자 조합의 평가
연산자 조합 평가 절차는 다음과 같다.
- 조합의 피연산자 표현식들을 평가한다.
- 연산자가 나타내는 함수를 인수(피연산자들의 값)들에 적용한다.
이 평가 규칙은 재귀적이다. 즉, 1을 수행하기 위해서 피연산자에 올 수 있는 연산자 조합을 평가해야한다.

이 평가 과정은 tree 형태로 시각화 할 수 있는 트리 누산(tree accumulation)으로 볼 수 있다.
함수 적용의 치환 모형
주어진 함수적용을 평가할 때, 함수의 각 매개변수를 해당 인수로 치환해서 함수의 반환 표현식을 평가한다.
ex) square(1) + square(2) -> (1 * 1) + (2 * 2) -> 연산의 조합을 평가
보통 해석기들은 함수 본문 텍스트의 매개변수를 치환하는 식으로 함수 적용을 평가하지는 않는다. 실제로는 매개변수에 대한 지역 환경을 이용해서 '치환'을 처리한다.
(참고) 가변데이터를 사용하는 함수는 치환 모형으로는 제대로 적용할 수 없기때문에 보다 정교한 함수 적용 모형이 필요하다.
조건부 표현식과 술어
술어 ? 귀결-표현식 : 대안-표현식
- 원시 술어
<, >, <=, >=, ===, !== - 복합 술어
논리 조합 연산(&&, ||, !)
&& || 는 연산자가 아니라 구문형이다. 따라서 우변에 오는 표현식이 항상 평가되지는 않는다.
인수 우선 평가 vs 정상 순서 평가
- 인수 우선 평가
- 함수, 인수표현식을 먼저 평가한 뒤 인수를 대입하는 방식
- 같은 표현식이 여러 번 평가되어서 생기는 비효율을 피할 수 있다.
- JS 해석기가 실제로 사용하는 평가방식
- 정상 순서 평가
- 연산자들과 원시함수들만 관여하는 표현식이 될 때까지 완전히 전개한 후 축약하는 방식
- 같은 표현식이 여러번 평가되어 비효율이 발생할 수 있다.
- 겉으로 보기에 무한한 자료 구조를 제한된 형태로 처리하는
스트림처리
에 유용할 수 있다.
function p() { return p(); }
function test(x, y) {
return x === 0 ? 0 : y;
}
test(0, p());
위 코드에서 인수 우선 평가, 정상 순서 평가시 각각 어떻게 동작하게 되는가?
- 인수 우선 평가 : test(0, p()) 에서 p()를 평가 -> 재귀 stack overflow
- 정상 순서 평가 : text(0, p()) -> 0 === 0 ? 0 : p() -> return 0 (p()가 평가되기 전에 프로그램의 실행이 종료된다)
지역 이름과 스코프
함수의 매개변수는 그 이름(즉, 지역 이름)이 함수 본문 내에서만 유효한데, 이 때 이름이 함수 선언에 바인딩되었다라고 한다.
주어진 이름의 바인딩이 유효하게 유지되는 문장의 집합을 그 이름의 범위(scope)라고 부른다.
JavaScript에서는 함수가 호출될 때 주어진 인수로 범위가 설정되는데, 이 방식을 어휘순 범위 적용(lexical scoping)이라고 한다.
여기서 lexical은 일상 언어에서 말하는 사전순과는 다른 의미로, 컴파일러(또는 해석기)가 어휘 분석 과정에서 소스 코드의 토큰들을 인식하는 순서(위에서 아래, 왼쪽에서 오른쪽)를 의미한다.
동적 범위(dynamic scope)와 대조된다는 점에서 정적 범위(static scope)라고 부르기도 한다.
'프로그래밍 > SICP' 카테고리의 다른 글
닫힘 성질을 충족하는 데이터 구조 설계(1) (0) | 2024.02.24 |
---|---|
거듭제곱, 최대공약수, 소수판정 최적화 (+ 확률에 의한 판정) (0) | 2024.02.20 |
고차함수를 이용한 추상화 (0) | 2024.02.15 |
꼬리재귀(tail-recursion)와 꼬리 호출 최적화(TCO) (0) | 2024.02.01 |
선언적 vs 명령적 (0) | 2024.01.30 |