많은 분들이 Common Lisp을 함수형 프로그래밍 언어로 알고 계신 것 같습니다. 이런 견해는
함수형 언어를 어떻게 정의하느냐에 따라, 맞는 견해일 수도 있고, 부적절한 표현일 일 수도
있습니다. 이번에는 제가 이해하고 있는 함수형 언어에 대해 이야기해 보겠습니다. 제 견해에
틀린 부분이나 부정확한 부분이 있다면 지적해 주시기 바랍니다.
먼저 함수형 언어를 넓은 의미에서 정의하면, Common Lisp은 함수형 언어의 조건을 다 갖추고 있습니다.
다음의 조건 4가지를 충족시키면, 그 함수는 일급 함수(fisrt-class function)라고 부르고, 일급
함수를 지원하는 언어는, '전통적인 의미'에서의 함수형 언어라고 부를 수 있습니다.
1) 함수 객체를 동적으로 생성할 수 있다.
2) 함수 객체를 변수에 대입할 수 있다.
3) 함수 객체를 함수의 인수로 전달할 수 있다.
4) 함수 객체를 함수의 반환값으로 반환할 수 있다.
특히 위의 세 번째와 네 번째 조건을 충족시키는 함수를 고차 함수(higher-order function)라고
부릅니다.
Common Lisp은 아마도 위의 네가지 조건 모두를 만족시키는 최초의 언어일 것입니댜.
그런데 문제는 요즘 새로 등장하는 언어들 거의 대부분이 위의 네 조건을 모두 충족시키고 있다는
것입니다(리습을 흉내내고 있다고 봐도 무방합니다). JavaScript마저도 위의 네 조건을 모두 충족시키고
있는데, 그렇다면 JavaScript도 함수형 언어라고 불러야 합니다.
더 심각한 문제는, Common Lisp을 함수형 언어로 인정한다 할지라도, Common Lisp이라는 언어를
과연 함수형 언어라는 하나의 카테고리로 규정할 수 있는가 하는 것입니다. 저의 견해는
No입니다. CLOS를 내장한 이후부터는 Common Lisp은 이미 객제지향 언어입니다. 또한 진정한
'메타 프로그래밍 언어'(즉, 매크로 언어)라고도 규정할 수도 있습니다. Common Lisp이라는 언어
자체는 계속 진화해 왔고, 앞으로도 그럴 것입니다. 따라서 Common Lisp을 함수형 언어라는
하나의 카테고리에만 담을 수는 없습니다.
하지만 Common Lisp에는 위에서 제가 말한 것처럼, 분명 함수형 언어로서 갖추어야할 요소들을,
충분하지는 않지만, 어느 정도 갖추고 있는 것은 분명합니다.
그러면 지금부터는 요즘 각광받기 시작하고 있는 '엄격한' 의미에서의 함수형 언어에 대해 말해
보겠습니다. 객체지향 프로그래밍이 갖는 문제점을 극복하고자 하는 대안으로서 요즘 주목받고
있는 '함수형 언어'는 위의 4가지 조건에 더해서, immutable 자료형을 기본(default)으로
제공해야 합니다. 이 조건을 하나 더 충족시켜야, 요즘에 말하는, 진정한 의미의 함수형 언어라고
말할 수 있습니다. immutable 자료형을 기본으로 하면, 메모리 소요량도 많아지고 처리 시간도
길어지는데, 왜 굳이 immutable 자료형을 기본으로 할까요? 그것은 immutable 자료형을 기반으로
연산을 수행하면, 프로그램의 복잡도가 엄청나게 줄어들 수 있기 때문입니다.
과거에 절차지향 프로그래밍의 문제점을 극복할 수 있는 대안으로 객체지향 프로그래밍이
등장한 이유가 무엇이었나요? 전역 변수의 사용을 줄이고, 변수를 클래스 안에 가두어 놓은 후에,
클래스 내의 멤버변수만 접근 가능하도록 '강제'한 이유가 무엇입니까? 그 이유는 전역 변수의 경우에는
프로그래밍 내의 어떤 함수에서도 접근이 가능해서, 그에 따라 어떤 함수가 그 변수를 건드렸는지
추적하기 무지무지 어렵기 때문이지 않았습니까? 물론 전역 변수를 많이 사용해서 프로그래밍한다
해도, 프로그래머가 아주 아주 조심스럽고 세심하게 프로그래밍하면 그 프로그램은 잘 돌아갈 수
있겠죠. 하지만 그렇게 세심하고 꼼꼼한 프로그래머도, 자신이 짠 프로그래밍 소스 코드를 2개월
정도 지나 들여다 봐도 자신이 짠 코드를 잘 이해하지 못하는데, 하물며 다른 사람이 짠 코드를
유지/보수해야 하는 입장에서는, 전역 변수의 남발이 악의 화신으로 느껴질 겁니다. 그래서
사람들이 객체지향 프로그래밍으로 많이 돌아섰지요. 그런데 여기서 한가지 중요한 원리가 발견됩니다.
그것은 변수의 값을 변경할 수 있는 함수들의 범위를 줄였다는데 있습니다. 그렇다면 상태를 유지하는
변수가 아예 없다면 어떻게 될까요? 바로 이것이 요즘에 등장한 함수형 언어들이 추구하는 목표입니다.
그런데 객체 지향 프로그래밍도, 설계하고자 하는 클래스의 크기가 커지거나, 다른 클래스에
의존하는 내부 변수들의 수가 증가할수록, 그리고 상속 관계가 복잡해질수록, 클래스 내부 변수를
건드리는 멤버 함수들의 수가 더불어 증가하기 마련입니다. 그래서 그 클래스 내부의 변수들을,
어떤 멤버 함수 내에서 건드리는 지 추적하는 일도 만만치 않은 일이 되어 버립니다. 전역 변수
관리할 때와 비슷한 현상이 나타나기 시작한다는 것이지요.
여기서 함수형 언어에서의 immutable 자료형의 진가가 드러나게 됩니다. 함수형 언어에서는
상태(state)를 저장하는 변수의 사용을 없애는 것을 목표로 함니다. 하지만, 상태를 저장하는 변수를
전혀 안쓸 수는 없습니다. 그래서 변수의 상태값을 변경하는 겻을 오히려 예외적인 상황으로 간주합니다.
그렇게 되면 디버깅할 때 디버깅의 단위가 함수 하나로 국한됩니다. 객체 지향
프로그래밍에서처럼, 클래스 내의 다른 멤버 함수가 클래스의 내부 변수를 언제 어떻게 건드리는지
전혀 신경쓸 필요가 없어집니다.
따라서 '프로그램의 복잡도를 줄여준다'는 의미로, 그리고 그것을 실현하기 위해 immutable
자료형을 기본으로 제공해야 한다는 의미로 함수형 언어를 정의한다면, Common Lisp은 함수형
언어가 아닙니다.