Lisp가 남달랐던 점
2001년 12월 (2002년 5월 개정)
(이 글은 LL1 메일링 리스트의 몇 가지 질문에 대한 답변으로 작성되었습니다. 현재 Revenge of the Nerds에 포함되어 있습니다.)
1950년대 후반 McCarthy가 Lisp를 설계했을 때, Lisp는 기존 언어들과는 급진적으로 달랐으며, 그중 가장 중요한 언어는 Fortran이었습니다.
Lisp는 아홉 가지 새로운 아이디어를 담고 있었습니다:
1. 조건문 (Conditionals). 조건문은 if-then-else 구조입니다. 우리는 이제 이를 당연하게 여깁니다. 이것들은 Lisp를 개발하는 과정에서 McCarthy에 의해 발명되었습니다. (당시 Fortran은 기본 하드웨어의 분기 명령에 기반한 조건부 goto만 가지고 있었습니다.) Algol 위원회에 참여했던 McCarthy는 조건문을 Algol에 도입했고, 그로부터 대부분의 다른 언어로 퍼져나갔습니다.
2. 함수 타입 (A function type). Lisp에서 함수는 일급 객체입니다. 즉, 정수, 문자열 등과 같은 데이터 타입이며, 리터럴 표현을 가지고 변수에 저장될 수 있고, 인수로 전달될 수 있는 등입니다.
3. 재귀 (Recursion). 재귀는 Lisp 이전에 물론 수학적 개념으로 존재했지만, Lisp는 이를 지원한 최초의 프로그래밍 언어였습니다. (함수를 일급 객체로 만드는 것 자체에 암묵적으로 내포되어 있다고 볼 수 있습니다.)
4. 새로운 변수 개념 (A new concept of variables). Lisp에서 모든 변수는 사실상 포인터입니다. 타입은 변수가 아닌 값에 있으며, 변수를 할당하거나 바인딩하는 것은 포인터가 가리키는 대상이 아니라 포인터 자체를 복사하는 것을 의미합니다.
5. 가비지 컬렉션 (Garbage-collection).
6. 표현식으로 구성된 프로그램 (Programs composed of expressions). Lisp 프로그램은 표현식의 트리로 구성되며, 각 표현식은 값을 반환합니다. (일부 Lisp에서는 표현식이 여러 값을 반환할 수 있습니다.) 이는 표현식과 문장을 구분하는 Fortran 및 대부분의 후속 언어와 대조됩니다.
Fortran에서 이러한 구분이 있는 것은 자연스러웠습니다. (펀치 카드 입력 형식을 사용했던 언어에서 놀랄 일도 아니지만) 언어가 라인 지향적이었기 때문입니다. 문장을 중첩할 수 없었습니다. 따라서 수학적 연산을 위해 표현식이 필요했지만, 다른 어떤 것도 값을 반환하게 할 이유가 없었습니다. 그 값을 기다리는 것이 있을 수 없었기 때문입니다.
이러한 제약은 블록 구조 언어의 등장과 함께 사라졌지만, 그때는 이미 너무 늦었습니다. 표현식과 문장의 구분은 확고하게 자리 잡았습니다. 이는 Fortran에서 Algol로, 그리고 그들의 후손 언어들로 퍼져나갔습니다.
언어가 전적으로 표현식으로만 구성되면, 원하는 방식으로 표현식을 조합할 수 있습니다. 예를 들어 (Arc 문법을 사용하여) 다음과 같이 말할 수 있습니다.
(if foo (= x 1) (= x 2))
또는
(= x (if foo 1 2))
7. 심볼 타입 (A symbol type). 심볼은 포인터를 비교하여 동등성을 테스트할 수 있다는 점에서 문자열과 다릅니다.
8. 심볼 트리 (trees of symbols)를 사용한 코드 표기법.
9. 항상 사용 가능한 전체 언어 (The whole language always available). 읽기 시간(read-time), 컴파일 시간(compile-time), 런타임(runtime) 사이에 실질적인 구분이 없습니다. 코드를 읽으면서 컴파일하거나 실행할 수 있고, 컴파일하면서 코드를 읽거나 실행할 수 있으며, 런타임에 코드를 읽거나 컴파일할 수 있습니다.
읽기 시간에 코드를 실행하면 사용자가 Lisp의 문법을 재프로그래밍할 수 있습니다. 컴파일 시간에 코드를 실행하는 것은 매크로의 기반입니다. 런타임에 컴파일하는 것은 Emacs와 같은 프로그램에서 Lisp가 확장 언어로 사용되는 기반입니다. 그리고 런타임에 읽는 것은 프로그램들이 s-표현식(s-expressions)을 사용하여 통신할 수 있게 하는데, 이는 최근 XML로 재발명된 아이디어입니다.
Lisp가 처음 발명되었을 때, 이 모든 아이디어는 1950년대 후반에 사용 가능했던 하드웨어에 의해 크게 좌우되던 일반적인 프로그래밍 관행과는 거리가 멀었습니다.
시간이 흐르면서, 일련의 인기 있는 언어들에 구현된 기본 언어는 점차 Lisp를 향해 진화해왔습니다. 1번부터 5번까지는 이제 널리 퍼져 있습니다. 6번은 주류에서 나타나기 시작했습니다. Python은 7번의 한 형태를 가지고 있지만, 이에 대한 문법은 없는 것 같습니다. 8번은 (9번과 함께) Lisp 매크로를 가능하게 하는 것인데, 아마도 (a) 괄호나 그만큼 나쁜 무언가가 필요하고, (b) 마지막으로 그만큼의 힘을 더하면 더 이상 새로운 언어를 발명했다고 주장할 수 없고, 단지 Lisp의 새로운 방언을 설계했다고만 말할 수 있기 때문에 아직까지 Lisp에만 고유한 특징입니다 ; -)
오늘날의 프로그래머들에게는 유용하겠지만, Lisp를 다른 언어들이 채택한 임시방편적인 것들과의 차이점으로 설명하는 것은 이상합니다. 아마도 McCarthy는 그렇게 생각하지 않았을 것입니다. Lisp는 Fortran의 실수를 고치기 위해 설계된 것이 아니라, 계산의 공리화를 시도하는 과정의 부산물로 탄생했습니다.