맨위로가기

리스프

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

리스프(Lisp)는 1958년 존 매카시가 개발한 프로그래밍 언어로, 람다 대수를 기반으로 기호 데이터를 다루는 데 특화되어 있다. 초기에는 IBM 704에서 인터프리터가 구현되었으며, 가비지 컬렉션과 같은 기능을 선구적으로 도입했다. 리스프는 S-표현식(S-expressions)을 사용하여 코드와 데이터를 표현하며, 함수형 프로그래밍, 매크로 시스템, 자동 메모리 관리와 같은 특징을 갖는다. 주요 방언으로는 Common Lisp, Scheme, Clojure 등이 있으며, 인공지능, 수식 처리, 임베디드 스크립팅, 게임 개발 등 다양한 분야에서 활용된다. 리스프는 객체 지향 시스템을 지원하며, 여러 운영 체제가 리스프를 기반으로 개발되었다.

더 읽어볼만한 페이지

  • 1958년 개발된 프로그래밍 언어 - 알골 (프로그래밍 언어)
    알골은 1950년대 후반 유럽 학자들이 개발한 명령형 프로그래밍 언어로서, BNF 표기법으로 문법이 기술되고 구조화된 프로그래밍 형태를 갖추어 이후 여러 언어에 영향을 주었으며, 특히 알골 60은 재귀 호출 지원으로 소프트웨어 모듈화와 컴퓨터 범용화에 기여하고 프로그래밍 개념 표준 용어 제공에 중요한 역할을 했다.
  • 리스프 - AI 겨울
    AI 겨울은 인공지능 연구에 대한 자금 지원과 관심이 크게 감소했던 시기를 가리키며, 기계 번역의 어려움, 신경망의 한계, 전문가 시스템 문제, 5세대 컴퓨터 실패 등의 요인으로 여러 차례 침체기를 겪었으나, 2000년대 이후 음성 및 이미지 인식 분야에서 성과를 거두며 부흥했고, 2022년 이후 대규모 언어 모델 등장으로 관심과 투자가 폭발적으로 증가했다.
  • 리스프 - 리스프 머신
    리스프 머신은 Lisp 언어의 효율적인 실행을 위해 설계된 컴퓨터 시스템으로, 인공지능 연구와 컴퓨터 그래픽스 분야에 영향을 미쳤으나 상업적 성공은 거두지 못했고, 기술적 유산은 현재까지 연구되고 있다.
  • 리스프 프로그래밍 언어 계열 - 클로저 (프로그래밍 언어)
    클로저는 리치 히키가 개발한 JVM 기반의 함수형 프로그래밍 언어로, 자바와의 호환성을 특징으로 하며 불변 데이터 구조와 STM을 활용한 동시성 관리, 그리고 REPL 환경, 매크로 시스템 등의 기능을 제공한다.
  • 리스프 프로그래밍 언어 계열 - 커먼 리스프
    커먼 리스프는 1980년대 초 여러 리스프 방언 통합 시도에서 시작된 언어로, S-표현식 문법, 다양한 자료형, 일급 함수, 매크로, CLOS를 특징으로 하며, ANSI 표준으로 정의되어 다양한 분야에서 활용된다.
리스프 - [IT 관련 정보]에 관한 문서
기본 정보
LISP 로고
LISP 로고
발표 연도1960년
설계자존 매카시
개발자스티브 러셀
티모시 P. 하트
마이크 레빈
패러다임다중 패러다임
함수형
절차적
반사
메타
자료형동적
강한
영향 받은 언어정보 처리 언어 (IPL)
영향을 준 언어CLIPS
CLU
COWSEL
Dylan
Elixir
Excel
Forth
Haskell
Io
Ioke
JavaScript
Julia
Logo
Lua
ML
Nim
Nu
OPS5
Perl
POP-2
POP-11
Python
R
Rebol
Red
Ruby
Scala
Swift
Smalltalk
Tcl
Wolfram Language
방언

2. 역사

리스프(LISP영어)는 매사추세츠 공과대학교(MIT)의 존 매카시가 1958년 개발을 시작하여[84][93] 1960년 논문을 통해 발표한 프로그래밍 언어이다.[100][14][86] 이 언어는 람다 대수 이론에 기반하여 설계되었으며, 처음부터 기호 데이터를 다루는 문제 해결에 적합하도록 만들어졌다. 이 때문에 당시 다른 언어에서는 보기 힘들었던 아톰(atom)이나 리스트(list)와 같은 새로운 데이터 구조를 사용했다.

최초의 리스프 인터프리터는 존 매카시의 동료들과 학생들의 도움으로 IBM 704 컴퓨터 상에서 구현되었으며, 특히 대학원생이었던 스티브 러셀의 기여가 컸다.[16][17] 초기 리스프는 IBM 704 하드웨어의 영향을 받아 리스트 처리 함수의 이름(`car`, `cdr`)이 정해졌으며,[18][94][95] 초창기부터 가비지 컬렉션 기능을 도입했다.[85][20]

리스프는 특정 시점에 완성된 형태로 설계된 것이 아니라, 사용자들의 요구와 새로운 기능 실험을 거치며 꾸준히 발전해왔다. 이 과정에서 수많은 방언(dialect)들이 생겨났는데, 이는 리스프의 유연성을 보여주는 동시에 표준화의 필요성을 제기하기도 했다. 초기에는 산술 연산 속도가 느리다는 단점이 있었으나, 성능 좋은 컴파일러들이 개발되면서 점차 해결되었다.[19] 리스프는 특히 인공지능(AI) 연구 분야와 밀접한 관계를 맺으며 발전했으며,[21] 운영체제 셸, 글 편집기(Emacs Lisp), CAD(AutoLISP) 등 다양한 소프트웨어의 확장 언어로도 널리 사용되었다.

1980년대에 들어 여러 방언들을 통합하려는 노력이 이루어졌고, 그 결과로 커먼 리스프(Common Lisp)가 탄생하여 1994년 ANSI 표준으로 제정되었다. 한편, 1975년 개발된 스킴(Scheme)은 간결함과 명확한 의미론을 추구하며 리스프의 또 다른 주요 흐름을 형성했다. 이 두 방언은 리스프의 발전에 큰 영향을 미쳤다.

리스프는 60년이 넘는 긴 역사 속에서 끊임없이 진화하며 현대에도 여전히 여러 분야에서 활발하게 사용되고 연구되는 언어이다. 1990년대에 잠시 주춤하기도 했으나, 2000년대 이후 다시금 주목받으며 새로운 방언과 커뮤니티 활동이 이어지고 있다.[36][37]

리스프 계열 언어의 대략적인 흐름
1960196519701975198019851990199520002005201020152020
LISPLISP I, 1.5, LISP 2(폐기)colspan="11" |
Maclispcolspan="1" |맥리스프colspan="7" |
Interlispcolspan="2" |인터리스프colspan="6" |
ZetaLispcolspan="3" |리스프 머신 리스프colspan="5" |
Schemecolspan="3" |Scheme
NILcolspan="4" |NILcolspan="7" |
Common Lispcolspan="5" |커먼 리스프
Tcolspan="5" |Tcolspan="5" |
Emacs Lispcolspan="6" |Emacs Lisp
AutoLISPcolspan="6" |AutoLISP
ISLISPcolspan="7" |ISLISP
EuLispcolspan="7" |EuLispcolspan="2" |
PicoLispcolspan="6" |PicoLisp
Racketcolspan="7" |Racket
Arccolspan="10" |Arc
Clojurecolspan="10" |Clojure
LFEcolspan="10" |LFE
Hycolspan="11" |Hy


2. 1. 초기 개발

리스프(LISP영어)는 1958년 가을, 존 매카시가 매사추세츠 공과대학교(MIT)의 통신 과학 조교수로 부임하면서 개발되기 시작했다.[84][93] 매카시는 1960년 4월 ACM의 학회지 Communications of the ACM영어에 "기호 표현의 재귀 함수와 기계에 의한 계산, 파트 I"(Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I영어)이라는 제목의 논문을 발표하여 리스프의 설계를 공개했다.[14][86] 이 논문에서 그는 몇 가지 간단한 연산자와 처치(Church)의 람다 대수에서 빌려온 익명 함수 표기법을 사용하면 튜링 완전한 알고리즘 언어를 만들 수 있음을 보였다. 또한, 자신을 평가할 수 있는 메타 순환 평가기(meta-circular evaluator)를 기술할 수 있음을 보여주었다.

정보 처리 언어(IPL)는 1955년 또는 1956년에 등장한 최초의 인공 지능 언어로, 리스트 처리나 재귀와 같은 리스프의 핵심 개념 중 일부를 이미 포함하고 있었다. 하지만 리스프가 등장하면서 인공지능 분야에서 점차 주된 언어로 자리 잡게 되었다.

매카시의 초기 아이디어는 대괄호로 묶인 "M-표현식"을 사용하는 것이었으나, 실제 구현 과정에서는 이를 S-표현식으로 변환하여 사용했다. 예를 들어, M-표현식 `car[cons[A,B]]`는 S-표현식 `(car (cons A B))`와 동일하다. 리스프가 구현된 이후 프로그래머들은 간결한 S-표현식을 선호하게 되었고, M-표현식은 거의 사용되지 않게 되었다. 호레이스 에니아(Horace Enea)의 MLisp[15] 와 바우건 프랫의 CGOL에서 잠시 M-표현식이 다시 시도되기도 했다.

최초의 리스프 인터프리터는 매카시의 지도 아래 대학원생이었던 스티브 러셀IBM 704 컴퓨터에서 천공 카드를 이용하여 구현했다.[16] 러셀은 매카시의 논문을 읽고, 논문에서 이론적으로 제시된 리스프의 `eval` 함수를 실제 기계어로 구현할 수 있다는 것을 깨달았다. 매카시 자신은 `eval` 함수가 계산보다는 이론적 설명을 위한 것이라고 생각했지만, 러셀은 이를 실제로 구현하여 매카시를 놀라게 했다.[17] 매카시는 당시 상황을 다음과 같이 회고했다.

> 스티브 러셀이 "이 'eval'을 프로그래밍하는 게 어때?"라고 말했고, 나는 그에게 "허, 허, 이론과 실제를 혼동하고 있군. 이 'eval'은 계산이 아니라 읽기를 위한 것이야."라고 말했다. 하지만 그는 계속 진행했다. 즉, 그는 내 논문의 ''eval''을 컴파일러를 사용하여 IBM 704 기계어로 컴파일하여 소프트웨어 버그를 수정하고 이를 리스프 인터프리터로 광고했는데, 확실히 그랬다. 그래서 그 시점에서 리스프는 오늘날과 본질적으로 동일한 형태를 갖게 되었다...[17]

이 구현을 통해 리스프 표현식을 평가하고 실행할 수 있는 작동하는 인터프리터가 탄생했다.

초기 리스프 구현은 IBM 704의 하드웨어 구조에 영향을 받았다. 리스트의 첫 번째 요소를 가져오는 `car`(Contents of the Address part of Register number영어)와 나머지 리스트를 가져오는 `cdr`(Contents of the Decrement part of Register number영어) 연산은 IBM 704의 프로세서 레지스터 구조에서 유래한 이름이다.[18][94][95] 이 두 기본 연산은 이후 대부분의 리스프 방언에서 표준적인 리스트 처리 함수로 사용되고 있다.

리스프의 초기 버전으로는 1960년에 발표된 LISP I[85]과 1962년에 발표된 LISP 1.5[96]가 있다. LISP I 단계에서부터 이미 가비지 컬렉션 기능이 구현되어 있었다.[85] 또한, 초기에는 M-표현식이 이론적으로 제시되었지만, 실제 입력은 펀치 카드를 이용한 공백 구분 방식의 S-표현식으로 이루어졌다.[85] 1964년 출판된 서적 The Programming Language LISP: Its Operation and Applications영어에서는 이미 M-표현식 표기가 사라지고 현대적인 S-표현식 표기만 사용되었다.[97]

2. 2. LISP 1, 1.5, 2

존 매카시는 1958년 매사추세츠 공과대학교(MIT)에 재직하면서 리스프(LISP) 개발을 시작했다.[84][93] 그는 1960년 4월 ACM의 학회지 Communications of the ACMeng에 "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part Ieng"라는 제목의 논문을 발표하여 리스프의 설계를 공개했다.[14][86] 이 논문에서 매카시는 몇 가지 간단한 연산자와 알론조 처치람다 대수에서 빌려온 익명 함수 표기법을 사용하면 튜링 완전한 알고리즘 언어를 만들 수 있음을 보였다. 또한, 리스프 코드를 리스프 자체로 해석할 수 있는 메타 순환 평가기(meta-circular evaluatoreng) 개념을 제시했다.

최초의 리스프 인터프리터는 매카시의 지도 아래 대학원생이었던 스티브 러셀IBM 704 컴퓨터에서 천공 카드를 사용하여 구현했다.[16] 러셀은 매카시의 논문을 읽고, 이론으로 제시된 리스프의 `eval` 함수를 실제 기계어로 구현할 수 있다는 것을 깨달았다. 매카시는 처음에 `eval` 함수가 이론적 설명을 위한 것이라고 생각했지만, 러셀은 이를 IBM 704 기계어로 컴파일하여 작동하는 리스프 인터프리터를 만들어냈다.[17] 이 인터프리터는 리스프 표현식을 평가하는 데 사용될 수 있었다.

매카시의 초기 표기법은 대괄호로 묶인 "M-expressioneng"(M-표현식)을 사용했지만, 실제 구현에서는 괄호와 공백으로 구분되는 "S-expressioneng"(S-표현식)으로 변환되었다. 예를 들어, M-표현식 `car[cons[A,B]]`는 S-표현식 `(car (cons A B))`와 동일하다. 프로그래머들은 빠르게 S-표현식을 선호하게 되었고, M-표현식은 점차 사용되지 않게 되었다.

리스프는 IBM 704 컴퓨터에서 처음 구현되었는데, 이 컴퓨터의 프로세서 레지스터 구조에서 리스트를 다루는 기본적인 함수 이름이 유래했다. 리스트의 첫 번째 요소를 반환하는 함수는 `car`(Contents of the Address part of Register numbereng)에서,[94] 나머지 리스트를 반환하는 함수는 `cdr`(Contents of the Decrement part of Register numbereng)에서[18][95] 따왔다. 이 두 함수 이름은 이후 대부분의 리스프 방언에서 표준적으로 사용되었다.

1960년에 LISP I이 출시되었고,[85] 이미 이때부터 가비지 컬렉션 기능이 구현되어 있었다.[85] 또한, 초기에는 M-표현식으로 문서를 작성했더라도 실제 펀치 카드 입력은 공백으로 구분된 S-표현식 형태를 사용했다.[85] 1962년에는 팀 하트(Tim Hart)와 마이크 레빈(Mike Levin)이 MIT에서 리스프로 작성된 최초의 완전한 리스프 컴파일러를 구현했다. 이 컴파일러는 기존 인터프리터보다 훨씬 빠른 실행 속도를 보여주었으며,[19] 컴파일된 함수와 해석된 함수를 자유롭게 혼합하여 사용할 수 있는 증분 컴파일러 모델을 도입했다. 같은 해 LISP 1.5가 출시되었다.[96] MIT의 대학원생이었던 다니엘 에드워즈는 1962년 이전에 가비지 컬렉션 루틴을 개발했다.[20]

LISP 2는 LISP 1.5 이후에 계획되었던 버전으로 알려져 있으나, 개발이 중단되어 널리 사용되지는 못했다.

초기 리스프는 람다 대수에 기반하여 기호 데이터를 처리하는 데 강점을 가졌지만, 초기 버전에서는 산술 연산 속도가 느리다는 단점이 있었다. 그러나 이후 성능이 개선된 컴파일러가 등장하면서 이러한 문제는 점차 해결되었다. 리스프는 초기부터 인공지능 연구 분야에서 중요한 역할을 했으며, 이후 다양한 분야에서 확장 언어 등으로 활용되었다.

2. 3. 한국에서의 리스프 연구

주어진 원본 소스에는 '한국에서의 리스프 연구' 또는 '나카니시 마사카즈', 'KLISP'에 대한 내용이 포함되어 있지 않다. 따라서 해당 섹션에 내용을 채울 수 없다.

2. 4. 주요 방언의 등장

리스프는 특정 시점에 완성된 형태로 설계된 것이 아니라, 사용자들의 요구와 새로운 기능 실험을 거치며 꾸준히 발전해 왔다. 이러한 진화 과정 속에서 다양한 리스프 방언(버전)들이 등장하게 되었다.

1970년대에는 여러 중요한 리스프 방언들이 경쟁하며 발전했다. 이 시기를 대표하는 두 주요 방언은 매사추세츠 공과대학교(MIT)의 프로젝트 맥(MAC)에서 개발된 맥리스프(Maclisp)와, 볼트 베라넥 앤 뉴먼(Bolt Beranek and Newman, BBN) 사와 제록스 팰러앨토 연구소(Xerox PARC)가 공동으로 개발한 인터리스프(Interlisp)였다. 이 두 방언은 당시 가장 널리 사용되었다.

이 외에도 주목할 만한 방언들이 있었다. 포터블 스탠다드 리스프(Portable Standard Lisp)는 이름 그대로 다양한 컴퓨터 시스템으로 쉽게 이식할 수 있도록 설계된 것이 특징이었다. 맥리스프를 기반으로 한 파생 방언들도 등장했는데, 캘리포니아 대학교 버클리(UC Berkeley)에서 개발한 프란츠 리스프(Franz Lisp)와 MIT 인공지능 연구소에서 개발한 제타리스프(Zetalisp)가 대표적이다. 특히 제타리스프는 리스프 코드를 매우 효율적으로 실행하기 위해 전용 하드웨어인 리스프 머신에서 사용될 목적으로 개발되었다.

이러한 1970년대의 다양한 방언들은 이후 리스프의 발전에 큰 영향을 미쳤으며, 커먼 리스프(Common Lisp)와 스킴(Scheme)과 같은 후대 표준화된 방언들의 등장 배경이 되었다.

2. 5. 커먼 리스프와 스킴

리스프는 오랜 시간 동안 여러 사람의 필요에 따라 기능이 추가되고 실험을 거치며 발전해왔다. 이 과정에서 맥리스프, 인터리스프, 제타리스프 등 수많은 변종이 생겨났다. 이러한 다양성은 리스프의 유연성을 보여주기도 했지만, 동시에 표준의 부재로 인한 혼란을 야기하기도 했다.[49] 1980년대에 이르러 이러한 여러 리스프 방언들을 하나로 통합하려는 노력이 시작되었다. 리스프 변종 가운데 가장 널리 쓰이는 것으로는 커먼 리스프스킴을 들 수 있다. 이 두 언어는 리스프 개발의 두 가지 주요 흐름을 대표하며, 서로 다른 설계 철학을 가지고 있다.

커먼 리스프는 이러한 표준화 노력의 결과물이다. 1980년대에 ZetaLisp, NIL 등 주로 맥리스프 계열의 후속 언어들의 기능을 통합하여 리스프 산업 표준을 만들고자 했다.[49] 커먼 리스프는 기존 방언들의 다양한 기능을 포괄하는, 일종의 상위 집합(superset)으로 설계되었으며, 객체 시스템(CLOS)을 포함한 방대한 표준 라이브러리를 제공하는 범용 프로그래밍 언어를 지향한다. 또한 스킴의 영향을 받아 렉시컬 스코프(변수의 유효 범위가 코드를 작성할 때 결정되는 방식)와 렉시컬 클로저와 같은 현대적인 개념을 도입했다.[49] 이러한 노력은 1994년 ANSI 표준("ANSI X3.226-1994 Information Technology Programming Language Common Lisp") 제정으로 결실을 맺었다. 커먼 리스프는 다양한 운영체제와 하드웨어 플랫폼에서 구현되어[52][53] 실용적인 개발 환경을 제공한다.

스킴은 커먼 리스프와는 다른 철학을 가진 리스프 방언이다. 1975년 MIT 인공지능 연구소의 Guy L. Steele, Jr.와 Gerald Jay Sussman이 개발했으며[101], 이후 MIT의 컴퓨터 과학 교육 과정에서 중요한 역할을 했다. 특히, 유명한 교재인 《컴퓨터 프로그램의 구조와 해석》(SICP, 속칭 '마법사 책')에서 사용되었다.[101]

스킴은 최소주의(minimalism)를 지향하며, 매우 명확하고 단순한 의미론을 갖도록 설계되었다. 언어의 핵심 기능을 간결하게 정의하고, 적은 수의 기본적인 표현식 구성 규칙을 제공한다. 커먼 리스프보다 약 10년 먼저 설계된 스킴은 정적 스코프(렉시컬 스코프)를 도입하여 변수의 유효 범위를 명확히 했으며[91][92], 꼬리 호출 최적화(함수 마지막 동작이 자기 자신을 호출하는 경우, 스택을 더 사용하지 않도록 최적화하는 기법)와 완전한 지속(continuation, 프로그램의 남은 계산을 표현하는 자료 구조)과 같은 고급 기능을 표준으로 요구하는 경우가 많다. 이는 함수형 프로그래밍과 같은 특정 프로그래밍 스타일을 강력하게 지원한다. 스킴은 1990년에 IEEE 표준이 제정되었으며, 이후에도 지속적인 표준 개정(Revisedn Report on the Algorithmic Language Scheme)과 구현 요청(Scheme Requests for Implementation, SRFI)을 통해 발전하고 있다.

결론적으로, 커먼 리스프와 스킴은 리스프라는 공통 조상에서 나왔지만 서로 다른 길을 걸어왔다. 커먼 리스프는 기존의 다양한 리스프 기능들을 통합하여 실용적이고 강력한 범용 언어를 만드는 데 중점을 두었다. 반면, 스킴은 언어의 핵심 원리를 탐구하고 간결함과 명확성을 추구하며, 교육적인 목적과 이론적인 기반을 중요시했다. 이러한 철학의 차이는 두 언어의 표준 규모, 기능 집합, 그리고 주로 사용되는 분야 등에서 뚜렷하게 나타난다.

2. 6. 현대의 리스프

1990년대에 다소 쇠퇴했던 리스프는 2000년 이후 다시 관심을 받기 시작했다. 이러한 관심 증가는 주로 Common Lisp, Scheme, Emacs Lisp, Clojure, Racket 구현과 새로운 이식 가능한 라이브러리 및 애플리케이션 개발에 집중되었다.

많은 새로운 리스프 프로그래머들은 폴 그레이엄이나 에릭 S. 레이먼드와 같은 인물들의 글에 영향을 받아, 일부에서는 오래된 언어로 여겨졌던 리스프를 배우기 시작했다. 이들은 리스프를 통해 프로그래밍에 대한 새로운 시각을 얻었으며, 다른 언어에 비해 생산성이 높다고 평가하기도 한다.[36] 이러한 인식 변화는 과거 "AI 겨울" 시기나 1990년대 중반의 짧은 부흥기와는 대조적인 모습이다.[37]

2010년 기준으로, 활발하게 유지 관리되는 Common Lisp 구현은 11개에 달했다.[38] 오픈 소스 커뮤니티는 리스프를 위한 새로운 지원 환경을 구축했다. 예를 들어, CLiki는 Common Lisp 관련 정보를 모으는 위키이고, Common Lisp directory는 관련 자원을 목록화하며, 인기 있는 IRC 채널인 #lisp에서는 리스프 기반 인 lisppaste의 지원을 받아 코드 조각을 공유하고 의견을 나눌 수 있다. Planet Lisp[39]는 다양한 리스프 관련 블로그 글을 모아 보여주고, LispForum[40]에서는 사용자들이 리스프 관련 주제를 토론하며, Lispjobs[41]는 관련 채용 정보를 제공한다. 또한, 주간 뉴스 서비스인 ''Weekly Lisp News''도 운영되고 있다. ''Common-lisp.net''은 오픈 소스 Common Lisp 프로젝트를 위한 호스팅 서비스를 제공하며, Quicklisp[42]는 Common Lisp용 라이브러리 관리 도구로 사용된다.

리스프 탄생 50주년(1958–2008)은 LISP50@OOPSLA 행사에서 기념되었다.[43] 보스턴, 밴쿠버, 함부르크 등지에서는 정기적인 지역 사용자 모임이 열리고 있으며, 유럽 Common Lisp 모임, 유럽 리스프 심포지엄, 국제 리스프 컨퍼런스와 같은 행사도 개최된다.

Scheme 커뮤니티 역시 활발하게 활동하며 20개 이상의 구현을 유지 관리하고 있다. 2000년대에는 Chicken, Gambit, Gauche, Ikarus, Larceny, Ypsilon 등 여러 중요한 새 구현이 개발되었다. Scheme의 R5RS 표준[44]은 커뮤니티에서 널리 받아들여졌으며, SRFI 프로세스를 통해 많은 준 표준 라이브러리와 확장이 만들어졌다. 2003년 시작된 새로운 언어 표준화 노력은 2007년 R6RS Scheme 표준으로 이어졌다. 하지만 컴퓨터 과학 교육 분야에서 Scheme의 사용은 다소 줄어드는 추세이다. 일부 대학에서는 컴퓨터 과학 입문 과정에서 Scheme 대신 다른 언어를 사용하기 시작했으며,[45][46] MIT 역시 학부 컴퓨터 과학 프로그램과 대규모 온라인 공개 강좌(MOOC)에서 Scheme 대신 Python을 사용하고 있다.[47][48]

이 시기에는 Arc, Hy, Nu, Liskell, LFE (Lisp Flavored Erlang)와 같은 새로운 리스프 방언들도 등장했다. Julia 언어의 파서는 Scheme의 방언인 Femtolisp로 구현되었다. 2019년 10월에는 폴 그레이엄이 새로운 리스프 방언인 [http://paulgraham.com/bel.html Bel]의 사양을 발표하기도 했다.

현재 공식적으로 표준화된 리스프 방언으로는 R6RS Scheme, R7RS Scheme, IEEE Scheme,[58] ANSI Common Lisp, 그리고 ISO ISLISP가 있다.

3. 주요 특징

폴 그레이엄은 리스프가 포트란과 같은 초기 언어들과 구별되는 아홉 가지 주요 특징을 다음과 같이 제시했다.[59]


  • 조건문이 goto 문에 얽매이지 않음
  • 일급 함수 지원
  • 재귀를 핵심 제어 구조로 사용
  • 변수를 포인터처럼 다루며, 타입 정보는 값 자체에 둠
  • 자동 가비지 컬렉션 기능 제공
  • 프로그램 전체가 표현식으로 구성되며, 별도의 문(statement) 개념이 없음
  • 기호 데이터 타입이 문자열과 구분됨
  • 코드를 기호로 구성된 트리 형태로 표현 (많은 괄호 사용)
  • 언어 전체 기능을 로드 타임, 컴파일 타임, 런타임 등 언제든 사용 가능


리스프는 프로그램 코드 자체를 표준적인 데이터 구조(주로 리스트)로 직접 표현하는 최초의 언어 중 하나였다. 이러한 특징을 호모아이코닉(homoiconic)이라고 부른다. 이 덕분에 리스프 프로그램은 다른 리스프 프로그램을 데이터처럼 읽고, 조작하고, 심지어 생성할 수도 있다. 이는 리스프의 강력한 표현력의 원천이며, 특히 매크로 시스템과 메타 순환 평가에 유리한 환경을 제공한다.

조건문을 위한 `if-then-else` 구문은 원래 매카시가 포트란으로 체스 프로그램을 만들면서 고안한 것이다. 그는 이를 ALGOL 표준에 포함시키려 했으나 Algol 58에는 반영되지 못했다. 대신 리스프에서는 더 일반적인 형태인 `cond` 구조를 사용했다.[60] 이후 `if-then-else`는 Algol 60에 채택되어 널리 퍼지게 되었다.

리스프는 스몰토크 개발을 이끈 앨런 케이에게 큰 영향을 주었으며, 반대로 스몰토크의 영향도 받았다. 1970년대 이후 리스프 방언들은 객체 지향 프로그래밍의 특징들(클래스 상속, 인스턴스 캡슐화, 메시지 전달 등)을 받아들였다. 특히 Flavors 객체 시스템은 다중 상속믹스인 개념을 도입했으며, 이를 발전시킨 공통 리스프 객체 시스템(CLOS)은 다중 상속, 다중 디스패치를 지원하는 다중 메서드, 일급 제네릭 함수 등을 통해 유연하고 강력한 동적 디스패치를 제공한다. CLOS는 이후 많은 리스프 계열 언어(예: Scheme)의 객체 시스템 설계에 영향을 주었으며, 종종 메타객체 프로토콜이라는 반사적인 방식으로 구현되었다. 이는 객체 시스템 자체가 객체로 정의되고 조작될 수 있음을 의미한다. 리스프는 스몰토크에 이어 이러한 메타객체 시스템을 갖춘 초창기 언어 중 하나였다. 앨런 케이는 훗날 이러한 특징들의 결합 덕분에 스몰토크와 리스프만이 진정한 의미의 객체 지향 시스템이라고 평가하기도 했다.[61]

또한 리스프는 더 이상 사용되지 않는 메모리를 시스템이 자동으로 회수하는 자동 가비지 컬렉션 개념을 프로그래밍 언어에 도입했다. 세대별 가비지 컬렉션과 같은 현대적인 가비지 컬렉션 알고리즘의 발전은 리스프에서의 활용 경험에 크게 힘입었다.[62]

컴퓨터 과학자 에츠허르 데이크스트라는 1972년 튜링상 수상 강연에서 리스프를 다음과 같이 평가했다.

: 매우 기본적인 몇 가지 원칙을 기초로 하여, 그것[리스프]은 놀라운 안정성을 보여주었다. 그 외에도, 리스프는 일종의 가장 정교한 컴퓨터 응용 프로그램을 위한 운반체였다. 리스프는 농담으로 "컴퓨터를 오용하는 가장 지능적인 방법"이라고 묘사되었다. 나는 그 묘사가 훌륭한 찬사라고 생각하는데, 그것이 해방의 완전한 풍미를 전달하기 때문이다: 그것은 우리의 가장 재능있는 동료 인간들이 이전에는 불가능했던 생각을 하는 데 도움을 주었다.[63]

초기 컴퓨터 하드웨어의 제한된 성능 때문에 리스프는 인공지능 연구 분야 외에서는 포트란이나 ALGOL의 영향을 받은 C 언어만큼 대중적인 인기를 얻지는 못했다. 그러나 복잡하고 동적인 응용 프로그램을 개발하는 데 강점을 보여, 2010년대 들어 다시금 주목받고 있다.[64]

3. 1. S-표현식

리스프는 을 구분하지 않는 식 지향 언어이다. 모든 코드와 데이터는 '식'으로 작성되며, 식이 평가되면 값을 생성한다.

매카시는 1960년 논문[86]에서 두 가지 표현 방식을 제안했다. 하나는 코드와 데이터의 내부 표현인 S-표현식(Symbolic Expression영어, 줄여서 sexp)이고, 다른 하나는 S-표현식을 다루는 함수를 표현하기 위한 M-표현식(Meta Expression영어)이었다. 원래 매카시는 프로그램 코드는 M-표현식으로 작성하고 데이터만 S-표현식으로 다룰 생각이었으나, S-표현식으로 작성된 코드를 직접 실행하는 `eval` 함수가 구현되면서 상황이 바뀌었다. S-표현식은 프로그램 자체를 데이터처럼 다룰 수 있게 해주는 강력한 장점이 있었기 때문에, M-표현식은 점차 사용되지 않게 되었고 오늘날 거의 모든 리스프는 코드와 데이터를 모두 S-표현식으로 다룬다.

S-표현식의 가장 눈에 띄는 특징은 괄호를 많이 사용한다는 점이다. 이 때문에 "리스프는 '짜증나고 불필요한 괄호가 많다'(Lots of Irritating Superfluous Parentheses영어)의 약자다" 와 같은 농담이 생기기도 했다.[65] 하지만 이 단순하고 일관된 괄호 기반 구문은 리스프의 강력한 기능들을 가능하게 하는 핵심 요소이다. 구문이 규칙적이어서 컴퓨터가 코드를 분석하고 조작하기 쉽다. 예를 들어, XML과 S-표현식을 통합하는 XMLisp와 같이 대체 표기법을 사용하도록 확장할 수도 있다.

S-표현식은 리스프에 뛰어난 유연성을 부여한다. 리스프의 함수 자체가 S-표현식(주로 리스트)으로 작성되기 때문에, 함수를 일반 데이터처럼 취급하고 조작할 수 있다. 이는 다른 프로그램을 분석하거나 생성하는 프로그램, 즉 메타프로그래밍을 쉽게 작성할 수 있게 해준다. 많은 리스프 방언은 이 특징을 매크로 시스템을 통해 활용하여, 프로그래머가 언어 자체의 기능을 확장하는 것을 가능하게 한다.

S-표현식에서 리스트는 공백으로 구분된 요소들을 괄호로 묶어 표현한다. 예를 들어,



(1 2 "foo")



는 숫자 1, 2와 문자열 "foo"를 요소로 가지는 리스트이다. 이러한 값들은 별도의 타입 선언 없이 사용된다(암묵적 타이핑). 빈 리스트 ()는 특별한 기호 nil로 표현하기도 한다.

리스프 인터프리터는 입력된 S-표현식을 평가하여 값을 반환한다. 예를 들어, (+ 2 3)이라는 표현식은 덧셈 함수 +를 숫자 2와 3에 적용하여 5라는 결과를 반환한다. 하지만 숫자 5 자체를 입력하면 그대로 5가 반환된다. 이처럼 대부분의 데이터 형태는 자기 자신으로 평가된다.

평가를 원하지 않고 표현식 자체를 데이터로 사용하려면 quote 연산자나 그 축약형인 작은따옴표(')를 사용한다. 예를 들어, foo라는 기호를 입력하면 보통 foo라는 변수의 값이 평가되어 반환되지만, (quote foo) 또는 'foo라고 입력하면 기호 foo 자체가 반환된다.

Common Lisp와 Scheme 등에서는 백쿼트(backquote, `) 연산자(Scheme에서는 quasiquote영어라고도 함)도 지원한다. 백쿼트는 기본적으로 quote와 유사하게 평가를 막지만, 특별한 기호인 쉼표(,, unquote영어)와 쉼표-앳(,@, splice영어)을 사용하여 백쿼트된 표현식의 일부만 선택적으로 평가하여 그 결과를 삽입할 수 있게 해준다. 예를 들어 변수 snue의 값이 리스트 (bar baz)일 때, `(foo ,snue)`(foo (bar baz))로 평가되고, `(foo ,@snue)`(foo bar baz)로 평가된다. 백쿼트는 주로 매크로를 정의할 때 코드 템플릿을 만드는 데 유용하게 사용된다.[68][69]

quote로 생성된 리터럴 데이터는 프로그램 내에서 수정될 수 있지만, 이렇게 리터럴 상수를 직접 수정하는 것은 예기치 않은 문제를 일으킬 수 있어 일반적으로 권장되지 않으며, ANSI Common Lisp 표준에서는 이러한 행위의 결과를 정의되지 않은 동작으로 규정한다. 예를 들어 다음 코드는 좋지 않은 스타일이다.



(defun should-be-constant ()

'(one two three))

(let ((stuff (should-be-constant)))

(setf (third stuff) 'bizarre)) ; 좋지 않음!

(should-be-constant) ; (one two bizarre)를 반환할 수 있음



S-표현식의 인용(quoting영어) 개념은 더글러스 호프스태터 등이 철학에서의 자기 참조 개념과 연결하여 설명하기도 했다.

3. 2. 리스트 처리

리스프 리스트는 괄호로 묶이고, 요소들은 공백으로 구분되어 작성된다. 예를 들어, `(1 2 foo)`는 세 개의 ''원자'' `1`, `2`, 그리고 `foo`로 이루어진 리스트이다. 이 값들은 암시적으로 유형화되는데, 각각 두 개의 정수와 "심볼"이라고 불리는 리스프 특정 데이터 유형이며, 이를 선언할 필요는 없다.

빈 리스트 `()`는 특수한 원자 `nil`로도 표현된다. 이것은 리스프에서 원자이면서 동시에 리스트인 유일한 개체이다.

표현식은 전위 표기법을 사용하여 리스트로 작성된다. 리스트의 첫 번째 요소는 함수 이름, 매크로 이름, 람다 표현식 또는 "특수 연산자"의 이름이다. 리스트의 나머지 부분은 인수이다. 예를 들어, 함수 `list`는 인수를 리스트로 반환하므로 다음 표현식



(list 1 2 (quote foo))



는 `(1 2 foo)` 리스트로 평가된다. 앞의 예에서 `foo` 앞에 있는 "quote"는 인수를 평가하지 않고 반환하는 "특수 연산자"이다. 따옴표가 없는 모든 표현식은 둘러싸는 표현식이 평가되기 전에 재귀적으로 평가된다. 예를 들어,



(list 1 2 (list 3 4))



는 `(1 2 (3 4))` 리스트로 평가된다. 세 번째 인수는 리스트이며, 리스트는 중첩될 수 있다.

리스트 (42 69 613)의 박스 및 포인터 다이어그램


리스프 리스트는 단일 연결 리스트로 구현된다.[66] 이 리스트의 각 셀은 ''cons'' (Scheme에서는 ''pair'')라고 불리며, ''car''와 ''cdr''이라는 두 개의 포인터로 구성된다. 이는 각각 연결 리스트 문서에서 논의된 `data` 및 `next` 필드와 동일하다.

cons 셀로 구성할 수 있는 많은 자료 구조 중 가장 기본적인 것 중 하나가 ''proper list''라고 불린다. proper list는 특수한 `nil` (빈 리스트) 기호이거나, `car`가 데이터(리스트와 같은 다른 cons 구조일 수 있음)를 가리키고, `cdr`이 다른 proper list를 가리키는 cons이다.

주어진 cons가 연결 리스트의 헤드로 간주되면, 해당 car는 리스트의 첫 번째 요소를 가리키고, cdr은 리스트의 나머지 부분을 가리킨다. 이러한 이유로, `car` 및 `cdr` 함수는 연결 리스트의 일부인 cons를 참조할 때 (예: 트리 대신) `first` 및 `rest`라고도 불린다.

따라서 리스프 리스트는 C++ 또는 Java의 컨테이너 클래스의 인스턴스처럼 원자 객체가 아니다. 리스트는 연결된 cons의 집합일 뿐이다. 주어진 리스트를 참조하는 변수는 리스트의 첫 번째 cons에 대한 포인터일 뿐이다. 리스트의 순회는 리스트를 ''cdring down''하여 수행할 수 있다. 즉, 연속적인 cdr을 취하여 리스트의 각 cons를 방문하거나, 리스트에 함수를 매핑하기 위해 여러 고차 함수 중 하나를 사용할 수 있다.

cons와 리스트는 리스프 시스템에서 매우 보편적이기 때문에, cons와 리스트가 리스프의 유일한 자료 구조라는 오해가 흔히 있다. 사실, 가장 단순한 리스프를 제외한 모든 리스프에는 벡터 (배열), 해시 테이블, 구조체 등과 같은 다른 자료 구조가 있다.

괄호로 묶인 S-표현식은 연결 리스트 구조를 나타낸다. 동일한 리스트를 S-표현식으로 나타내는 방법에는 여러 가지가 있다. `cons`는 `(a . b)`와 같이 ''점 표기법''으로 작성할 수 있으며, 여기서 `a`는 car이고 `b`는 cdr이다. 더 긴 적절한 리스트는 점 표기법으로 `(a . (b . (c . (d . nil))))`로 작성할 수 있다. 이는 일반적으로 ''리스트 표기법''으로 `(a b c d)`로 축약된다. 부적절한 리스트[67]는 두 가지의 조합으로 작성할 수 있으며, 마지막 cdr이 `d`인 세 개의 `cons`의 리스트, 즉 `(a . (b . (c . d)))` 리스트를 `(a b c . d)`와 같이 완전히 지정된 형태로 표현할 수 있다.

리스프는 리스트에 접근하고 제어하기 위한 많은 내장 프로시저를 제공한다. 리스트는 임의의 수의 인수를 받아 해당 인수의 리스트를 반환하는 `list` 프로시저를 사용하여 직접 생성할 수 있다.

```lisp

(list 1 2 'a 3)

;Output: (1 2 a 3)

(list 1 '(2 3) 4)

;Output: (1 (2 3) 4)

```

리스트가 cons 쌍으로 구성되는 방식 때문에 `cons` 프로시저를 사용하여 리스트의 맨 앞에 요소를 추가할 수 있다. `cons` 프로시저는 리스트가 구성되는 방식 때문에 리스트 인수를 처리하는 방식에 있어 비대칭적이다.

```lisp

(cons 1 '(2 3))

;Output: (1 2 3)

(cons '(1 2) '(3 4))

;Output: ((1 2) 3 4)

```

`append` 프로시저는 두 개 이상의 리스트를 서로 덧붙인다. 리스프 리스트는 연결 리스트이므로 두 리스트를 덧붙이는 것은 점근적 시간 복잡도 O(n)를 갖는다.

```lisp

(append '(1 2) '(3 4))

;Output: (1 2 3 4)

(append '(1 2 3) '() '(a) '(5 6))

;Output: (1 2 3 a 5 6)

```

리스프 리스트는 단순 연결 리스트이므로 서로 구조를 공유할 수 있다. 즉, 두 리스트가 동일한 ''꼬리'' 또는 cons의 최종 시퀀스를 가질 수 있다. 예를 들어, 다음 Common Lisp 코드를 실행한 후:

```lisp

(setf foo (list 'a 'b 'c))

(setf bar (cons 'x (cdr foo)))

```

리스트 `foo`와 `bar`는 각각 `(a b c)`와 `(x b c)`이다. 그러나 꼬리 `(b c)`는 두 리스트에서 동일한 구조이다. 복사본이 아니다. `b`와 `c`를 가리키는 cons 셀은 두 리스트 모두에서 동일한 메모리 위치에 있다.

구조를 복사하지 않고 공유하면 성능이 극적으로 향상될 수 있다. 그러나 이 기술은 인수로 전달된 리스트를 변경하는 함수와 원치 않는 방식으로 상호 작용할 수 있다. `c`를 `goose`로 바꾸는 것과 같이 한 리스트를 변경하면 다른 리스트에도 영향을 미친다.

```lisp

(setf (third foo) 'goose)

```

이렇게 하면 `foo`가 `(a b goose)`로 변경되지만 이로 인해 `bar`도 `(x b goose)`로 변경된다. 이는 예상치 못한 결과일 수 있다. 이는 버그의 원인이 될 수 있으며, 인수를 변경하는 함수는 바로 이러한 이유로 ''파괴적''으로 문서화되어 있다.

함수형 프로그래밍 애호가들은 파괴적 함수를 피한다. 함수형 스타일을 선호하는 Scheme 방언에서는 파괴적 함수의 이름이 주의를 나타내는 느낌표 또는 "bang"으로 표시된다. 예를 들어 `set-car!` (''set car bang''이라고 읽음)은 cons의 car를 대체한다. Common Lisp 방언에서 파괴적 함수는 흔하다. `set-car!`에 해당하는 것은 "replace car"의 약자인 `rplaca`로 명명되었다. 그러나 Common Lisp에는 파괴적 함수를 더 쉽게 정의하고 사용할 수 있도록 하는 특수 기능인 `setf`가 포함되어 있으므로 이 함수는 거의 사용되지 않는다. Common Lisp에서 자주 사용되는 스타일은 프로토타입을 만들 때 기능적으로 (파괴적 호출 없이) 코드를 작성한 다음 안전하게 수행할 수 있는 곳에서 최적화로 파괴적 호출을 추가하는 것이다.

3. 3. 함수형 프로그래밍

폴 그레이엄은 리스프가 가진 중요한 특징 중 함수형 프로그래밍과 밀접하게 관련된 요소로 일급 함수재귀를 꼽았다.[59] 일급 함수는 함수를 다른 값들처럼 변수에 할당하거나 함수의 인수로 전달하고, 함수의 결과값으로 반환할 수 있게 하는 개념이다. 재귀는 함수가 자기 자신을 호출하여 문제를 해결하는 방식으로, 함수형 프로그래밍에서 반복문을 대체하는 주요 기법으로 사용된다.

리스프는 프로그램 코드가 표준 데이터 구조(주로 괄호로 둘러싸인 기호 트리)로 직접 표현되는 호모아이코닉 언어이다. 이 특징 덕분에 리스프 함수는 리스프 프로그램 내에서 쉽게 조작, 변경, 생성될 수 있으며, 이는 언어의 표현력을 높이고 구문 매크로나 메타 순환 평가에 유리하게 작용한다.

리스프에서는 lambda라는 특수 연산자를 사용하여 익명 함수를 만들 수 있다. lambda는 인수로 받을 변수 목록과 실행할 표현식을 받아 함수 객체를 생성한다. 예를 들어, 다음 코드는 인수를 하나 받아 1을 더하는 함수를 정의한다.



(lambda (arg) (+ arg 1))



이 람다 표현식은 일반 함수처럼 호출할 수 있다. 아래 코드는 위에서 정의한 익명 함수에 값 5를 전달하여 실행하고, 결과로 6을 반환한다.



((lambda (arg) (+ arg 1)) 5)



이름이 있는 함수는 defun 매크로를 사용하여 정의한다. defun은 람다 표현식을 특정 기호(함수 이름)에 저장하는 역할을 한다.



(defun foo (a b c d) (+ a b c d))



이는 내부적으로 setffdefinition을 사용하여 전역 환경에 함수 정의를 저장하는 것과 유사하게 동작한다. 예를 들어 (defun f (a) b...)는 개념적으로 다음 식과 유사하다.



(setf (fdefinition 'f) #'(lambda (a) (block f b...)))



여기서 setf는 첫 번째 인수 fdefinition 'f의 값을 새 함수 객체로 설정하는 데 사용되는 매크로이다. fdefinitionf라는 함수의 전역 함수 정의이다. #'는 함수 객체를 반환하는 특수 연산자 function의 약어이다.

리스프의 구문은 재귀적 정의에 매우 적합하여, 재귀를 이용한 문제 해결을 간결하게 표현할 수 있다. 다음은 인수의 계승을 계산하는 재귀 함수의 예시이다.



(defun factorial (n)

(if (<= n 1)

1

(* n (factorial (- n 1)))))



꼬리 재귀를 사용하면 다음과 같이 작성할 수도 있다. 이는 재귀 호출이 함수의 마지막 연산이 되도록 하여 최적화를 가능하게 한다.



(defun factorial (n &optional (acc 1))

(if (<= n 1)

acc

(factorial (- n 1) (* acc n))))



재귀 외에도 Common Lisp의 LOOP 매크로를 사용하여 반복적으로 계승을 계산할 수도 있다.



(defun factorial (n)

(loop for i from 1 to n

for fac = 1 then (* fac i)

finally (return fac)))



다음은 리스트를 인수로 받아 요소의 순서를 뒤집는 재귀 함수의 예시이다. (대부분의 리스프 구현에는 이미 내장된 `reverse` 함수가 있다.)



(defun reverse (l &optional acc)

(if (atom l)

acc

(reverse (cdr l) (cons (car l) acc))))



리스프는 자동 가비지 컬렉션 개념을 도입하여 프로그래머가 메모리 관리에 직접 신경 쓰지 않도록 도왔다. 이는 특히 함수형 프로그래밍에서 많은 임시 객체가 생성될 때 유용하다.[62]

에츠허르 데이크스트라는 1972년 튜링상 강연에서 다음과 같이 말했다.

:매우 기본적인 몇 가지 원칙을 기초로 하여, 그것[리스프]은 놀라운 안정성을 보여주었다. 그 외에도, 리스프는 일종의 가장 정교한 컴퓨터 응용 프로그램을 위한 운반체였다. 리스프는 농담으로 "컴퓨터를 오용하는 가장 지능적인 방법"이라고 묘사되었다. 나는 그 묘사가 훌륭한 찬사라고 생각하는데, 그것이 해방의 완전한 풍미를 전달하기 때문이다: 그것은 우리의 가장 재능있는 동료 인간들이 이전에는 불가능했던 생각을 하는 데 도움을 주었다.[63]

3. 4. 매크로 시스템

리스프 프로그램의 텍스트 표현은 기본 리스프 시스템에서 사용하는 내부 데이터 구조(연결 리스트, 기호, 숫자, 문자 등)와 동일한 형태를 가지며, 사람이 읽을 수 있도록 설명된 형태라는 점에서 다른 언어와 근본적인 차이가 있다.

리스프는 이러한 특징을 바탕으로 매우 강력한 매크로 시스템을 구현한다. 이는 C, Objective-C, C++ 프로그래밍 언어에서 사용되는 C 전처리기의 매크로와 유사하게, 컴파일 가능한 코드를 반환하는 역할을 한다. 하지만 C 전처리기 매크로와 달리, 리스프 매크로는 리스프 함수 자체이므로 리스프 언어가 가진 모든 기능을 활용하여 매크로를 작성할 수 있다는 장점이 있다.

또한, 리스프 코드는 리스트와 동일한 구조를 가지기 때문에, 언어에 내장된 모든 리스트 처리 함수를 사용하여 매크로를 만들 수 있다. 즉, 리스프가 데이터 구조에 대해 할 수 있는 모든 작업을 리스프 매크로는 코드에 대해서도 할 수 있는 것이다. 반면, 대부분의 다른 언어에서는 파서가 처리한 결과물이 언어 구현 내부에만 존재하여 프로그래머가 직접 조작하기 어렵다.

이러한 매크로 기능 덕분에 언어 내에서 효율적인 새로운 언어를 쉽게 개발할 수 있다. 예를 들어, 공통 리스프 객체 시스템(CLOS)은 매크로를 사용하여 리스프 언어의 확장 기능으로 깔끔하게 구현되었다. 이는 만약 애플리케이션 개발 시 다른 상속 메커니즘이 필요하다면, 다른 객체 시스템을 선택하여 사용할 수 있음을 의미한다. 이는 다중 상속을 지원하지 않고 이를 추가할 마땅한 방법이 없는 자바와 같은 다른 언어들과 대조되는 특징이다.

단순한 리스프 구현에서는 이러한 리스트 구조가 프로그램을 실행하기 위해 직접 해석된다. 함수는 말 그대로 인터프리터가 실행 시점에 따라가는 리스트 구조의 일부인 셈이다. 그러나 대부분의 주요 리스프 시스템은 컴파일러도 포함하고 있다. 컴파일러는 리스트 구조를 기계어바이트코드로 변환하여 실행 속도를 높인다. 이렇게 컴파일된 코드는 C와 같은 기존 언어로 컴파일된 코드만큼 빠르게 실행될 수 있다.

매크로는 컴파일 단계 이전에 확장되기 때문에 몇 가지 흥미로운 활용 가능성을 제공한다. 예를 들어, 프로그램 실행 중에 미리 계산된 테이블이 필요하다면, 매크로를 이용해 컴파일 시간에 해당 테이블을 미리 생성해 둘 수 있다. 이렇게 하면 컴파일러는 테이블 자체만 결과물에 포함시키면 되므로, 런타임에 테이블을 생성하기 위한 코드를 실행할 필요가 없어진다. 일부 리스프 구현에는 `eval-when`이라는 메커니즘이 있어서, 컴파일 시점(매크로가 필요할 때)에는 특정 코드가 존재하도록 하고, 최종적으로 생성되는 모듈에는 해당 코드가 포함되지 않도록 할 수도 있다.[70]

3. 5. 자동 메모리 관리

리스프의 리스트는 단순 연결 리스트 구조를 가지므로, 여러 리스트가 동일한 구조를 공유할 수 있다. 이는 두 리스트가 같은 '꼬리', 즉 리스트의 마지막 부분을 공유할 수 있다는 의미이다. 예를 들어, 다음 Common Lisp 코드를 실행하면:

```lisp

(setf foo (list 'a 'b 'c))

(setf bar (cons 'x (cdr foo)))

```

리스트 `foo`는 `(a b c)`가 되고, `bar`는 `(x b c)`가 된다. 이때 두 리스트의 꼬리 부분인 `(b c)`는 동일한 메모리 구조를 공유하며, 복사된 것이 아니다. 즉, `b`와 `c`를 가리키는 cons 셀은 두 리스트에서 같은 메모리 주소를 참조한다.

구조를 복사하지 않고 공유하는 방식은 성능을 크게 향상시킬 수 있다. 하지만 이 방식은 인수로 전달된 리스트를 변경하는 함수(파괴적 함수)와 예기치 않은 방식으로 상호작용할 수 있다. 예를 들어, `foo` 리스트의 세 번째 요소를 `c`에서 `goose`로 변경하면:

```lisp

(setf (third foo) 'goose)

```

`foo`는 `(a b goose)`로 바뀌지만, 공유된 구조 때문에 `bar` 역시 `(x b goose)`로 함께 변경된다. 이는 예상치 못한 결과일 수 있으며 버그의 원인이 되기도 한다. 이러한 이유로 인수를 직접 수정하는 함수는 '파괴적(destructive)'이라고 명시적으로 문서화된다.

함수형 프로그래밍에서는 이러한 파괴적 함수 사용을 지양한다. 함수형 스타일을 선호하는 Scheme 방언에서는 파괴적 함수의 이름 끝에 느낌표(`!`, '뱅'이라고 읽음)를 붙여 주의를 환기시킨다. 예를 들어, `set-car!`는 cons 셀의 car 부분을 교체하는 파괴적 함수이다. 반면, Common Lisp 방언에서는 파괴적 함수가 흔하게 사용된다. `set-car!`에 해당하는 함수로 `rplaca`("replace car"의 약자)가 있지만, Common Lisp에는 파괴적 함수를 더 쉽게 정의하고 사용할 수 있게 하는 `setf` 매크로가 있어 `rplaca`는 거의 사용되지 않는다. Common Lisp에서는 프로토타입을 만들 때는 함수형 스타일(파괴적 호출 없이)로 코드를 작성하고, 이후 최적화 단계에서 안전하다고 판단되는 부분에 파괴적 호출을 추가하는 방식이 자주 사용된다.

4. 문법

리스프는 초기에 원자(atom)와 리스트(list)라는 두 가지 기본적인 자료형을 가졌다. 리스트는 요소들의 유한한 순서열이며, 각 요소는 원자이거나 또 다른 리스트일 수 있었다. 원자는 숫자 또는 기호(symbol)였는데, 기호는 소스 코드에서 영숫자 문자열로 표현되며 변수 이름이나 기호 처리 데이터 등으로 사용되었다. 예를 들어, 리스트 `(FOO (BAR 1) 2)`는 기호 `FOO`, 리스트 `(BAR 1)`, 숫자 `2`라는 세 요소를 포함한다.

원자와 리스트의 중요한 차이는 원자가 변경 불가능하고 고유하다는 점이다. 소스 코드의 다른 위치에 동일하게 작성된 두 원자는 같은 객체를 나타낸다. 반면, 리스트는 각기 독립적인 객체로 생성되며 변경이 가능하고 다른 리스트와 구별될 수 있었다. 후기 리스프 방언에서는 더 다양한 데이터 타입이 도입되면서 원자의 개념은 상대적으로 중요성이 줄어들었다. 많은 방언에서는 여전히 'atom'이라는 술어를 제공하며, 이는 cons 셀이 아닌 모든 객체에 대해 참으로 정의된다.

리스프는 "식 지향" 언어로, 다른 많은 언어와 달리 을 구분하지 않는다. 모든 코드와 데이터는 S식(S-expression, Symbolic expression)이라는 괄호로 둘러싸인 리스트 형태로 작성된다. 식이 평가되면 값을 생성하며, 이 값은 다른 식의 일부가 될 수 있다. 이러한 특징은 리스프에 뛰어난 유연성을 부여하며, 코드 자체를 데이터처럼 다루는 메타 프로그래밍을 가능하게 한다. 많은 리스프 방언은 이 기능을 매크로 시스템을 통해 활용하여 언어 자체를 확장할 수 있도록 지원한다.

매카시는 1960년 논문[86]에서 내부 데이터 구조 표현인 S식과 함수를 나타내는 외부 표현인 M식(M-expression, Meta-expression)을 제안했다. 원래는 데이터 표현에 S식을, 프로그램 표현에 M식을 사용하려 했으나, S식으로 작성된 프로그램을 평가하는 `eval` 함수가 구현되면서 프로그램 자체를 데이터처럼 다룰 수 있는 S식의 장점이 부각되었다. 오늘날 대부분의 리스프 언어는 프로그램과 데이터 모두에 S식을 사용하며 M식은 거의 사용되지 않는다.

S식은 괄호를 많이 사용하는 특징 때문에 비판을 받기도 하지만, 이 정규화된 구문은 컴퓨터가 코드를 쉽게 분석하고 조작할 수 있게 하여 리스프의 강력한 메타 프로그래밍 능력을 뒷받침한다. 리스트는 공백과 괄호로 구분된 요소로 기술된다. 예를 들어, `(1 2 "foo")`는 숫자 `1`, `2`와 문자열 `"foo"`를 요소로 가지는 리스트이다. 빈 리스트 `()`는 `nil`로도 표현된다.

리스프 코드는 주로 읽기-평가-출력 루프(REPL, Read-Eval-Print Loop)라는 명령 줄 인터페이스를 통해 실행된다. 사용자가 S식 형태의 코드를 입력하면, 리스프 시스템은 다음 과정을 반복한다.

1. 읽기(Read): `read` 함수가 텍스트 S식을 입력받아 내부 데이터 구조(주로 리스트)로 변환한다.

2. 평가(Eval): `eval` 함수가 변환된 데이터 구조(코드)를 평가하여 결과를 생성한다. 기본적인 평가 규칙은 연산자 섹션에서 더 자세히 다룬다.

3. 출력(Print): `print` 함수가 평가 결과를 사용자에게 보여준다.

기본적인 REPL은 `(loop (print (eval (read))))`와 같은 간단한 코드로 구현될 수 있지만, 실제 REPL은 입력 편집, 기록, 오류 처리, 디버거 연동 등 다양한 편의 기능을 제공한다.

리스프는 일반적으로 조급한 평가(eager evaluation) 방식을 따른다. Common Lisp에서는 인수가 왼쪽에서 오른쪽 순서로 평가되지만(응용 순서), Scheme에서는 인수 평가 순서가 정해져 있지 않아 컴파일러 최적화의 여지를 남겨둔다.

4. 1. 연산자

리스프는 다른 언어들과 달리 을 구분하지 않으며, 모든 코드와 데이터는 식으로 작성된다. 식은 평가될 때 값을 생성하며, 다른 식 안에 포함될 수 있다.[86]

모든 식은 전위 표기법을 따르는 리스트 형태로 작성된다. 리스트의 첫 번째 요소는 함수, 연산자, 매크로, 또는 특수 형식(special form)의 이름이며, 나머지 요소들은 해당 연산의 인수가 된다. 예를 들어, 함수 list는 인수로 받은 값들을 리스트로 만들어 반환한다.

```lisp

(list 1 2 "foo")

```

위 식은 평가되어 (1 2 "foo")라는 리스트를 결과로 낸다. 만약 인수 중 일부가 또 다른 식이라면, 그 식은 포함된 전체 식이 평가되기 전에 먼저 재귀적으로 평가된다.

```lisp

(list 1 2 (list 3 4))

```

이 식은 (1 2 (3 4))라는 중첩된 리스트로 평가된다.

산술 연산자 역시 함수처럼 전위 표기법으로 사용된다. 알골 계열 언어들과 달리 리스프에는 별도의 연산자 개념이 없으며, 산술 연산은 임의 개수의 인수를 받을 수 있는 가변 인자 함수로 처리된다. 예를 들어, 다음 식은 10으로 평가된다.

```lisp

(+ 1 2 3 4)

```

이는 중위 표기법으로 표현하면 1 + 2 + 3 + 4와 같다. C 언어 스타일의 증가 연산자 ++와 유사한 기능은 incf라는 이름으로 구현되어 있다.

```lisp

(incf x)

```

위 코드는 (setq x (+ x 1))과 동일하게 변수 x의 값을 1 증가시키고, 그 새로운 값을 반환한다.

리스프는 "특수 연산자" 또는 "특수 형식"이라 불리는 요소들을 통해 제어 구조를 제공한다. 특수 형식은 일반 함수와 달리 인수를 평가하는 방식이 다르다. 예를 들어, 특수 형식 if는 세 개의 인수를 받는다. 첫 번째 인수를 평가한 값이 참(nil이 아닌 값)이면 두 번째 인수를 평가하고, 거짓(nil)이면 세 번째 인수를 평가한다.

```lisp

(if nil

(list 1 2 "foo")

(list 3 4 "bar"))

```

위 식은 첫 번째 인수가 nil(거짓)이므로 세 번째 인수인 (list 3 4 "bar")가 평가되어 (3 4 "bar")라는 리스트를 결과로 낸다.

논리 연산자로는 and, or, not이 제공된다. andor 연산자는 단락 평가를 수행한다. and는 첫 번째 nil 인수를 만나면 그 값을 반환하고 평가를 중단하며, 모든 인수가 참이면 마지막 인수의 값을 반환한다. or는 첫 번째로 nil이 아닌 인수를 만나면 그 값을 반환하고 평가를 중단하며, 모든 인수가 nil이면 nil을 반환한다.

```lisp

(or (and "zero" nil "never") "James" 'task 'time)

```

위 식에서 (and "zero" nil "never")는 두 번째 인수 nil을 만나 nil로 평가된다. 이후 or는 첫 번째 nil이 아닌 인수 "James"를 만나 "James"를 최종 결과로 반환한다.

4. 2. 조건문

리스프의 조건문은 초창기 언어들과 달리 `goto` 문에만 의존하지 않는 유연성을 가졌다.[59] 존 매카시는 포트란을 위해 `if-then-else` 구문을 고안했지만, 리스프 자체에는 이보다 더 일반적인 `''cond''` 구조를 도입했다.[60] `if-then-else` 구문은 이후 Algol 60에 채택되어 널리 퍼졌다. 리스프의 원래 조건 연산자인 `''cond''`는 나중에 보편화된 `if-then-else` 구조의 기초가 되었다.

리스프에서 `''if''`와 같은 조건문은 '특수 형식(special form)'으로 취급된다. 이는 일반적인 함수 호출과 문법적 형태는 유사하지만, 인수를 평가하는 방식에서 차이가 있다. 일반 함수는 모든 인수를 먼저 평가하지만, `''if''` 같은 특수 형식은 조건에 따라 특정 인수만 선택적으로 평가한다.

예를 들어, Common Lisp에서 `''if''`는 세 개의 인수를 받는다. 첫 번째 인수는 조건식이고, 이 조건식의 평가 결과가 참(`nil`이 아닌 모든 값)이면 두 번째 인수를 평가하고 그 결과를 반환한다. 만약 조건식의 결과가 거짓(`nil`)이면 세 번째 인수를 평가하고 그 결과를 반환한다.



(if (evenp 5) ; 조건식: 5가 짝수인가? (결과: nil, 거짓)

(list 1 2 "foo") ; 조건이 참일 때 평가될 식

(list 3 4 "bar")) ; 조건이 거짓일 때 평가될 식



위 예시에서 `(evenp 5)`는 5가 홀수이므로 `nil`(거짓)을 반환한다. 따라서 `''if''`는 세 번째 인수인 `(list 3 4 "bar")`를 평가하고, 그 결과인 리스트 `(3 4 "bar")`를 최종적으로 반환한다.

4. 3. 함수 정의

Lisp에서 함수를 정의하는 방법은 주로 `lambda` 특수 연산자와 `defun` 매크로를 사용한다.

`lambda`는 변수를 값에 바인딩하여 식 내에서 평가하는 데 사용되는 특수 연산자이다. 이는 익명 함수(이름 없는 함수)를 생성하는 데 주로 사용된다. `lambda`는 인수로 '인수 목록'과 '함수가 평가할 식'을 받는다. 함수가 반환하는 값은 평가된 마지막 식의 값이다.

예를 들어, 다음 식은 인수를 하나 받아 1을 더한 값을 반환하는 함수를 생성한다.



(lambda (arg) (+ arg 1))



이렇게 생성된 람다 표현식(익명 함수)은 이름이 있는 함수와 동일하게 호출할 수 있다. 다음 코드는 위에서 정의한 익명 함수에 값 5를 전달하여 실행하고, 결과로 6을 얻는다.



((lambda (arg) (+ arg 1)) 5) ; 결과는 6



이름이 있는 함수를 정의할 때는 `defun` 매크로를 사용한다. `defun`은 `lambda` 표현식을 특정 기호에 저장하여 명명된 함수를 만든다.



(defun 함수이름 (인수목록)

"선택적인 문서 문자열(docstring)"

함수 본문 식...)



예를 들어, 네 개의 숫자를 더하는 `foo`라는 함수는 다음과 같이 정의할 수 있다.



(defun foo (a b c d) (+ a b c d))



`(defun f (a) b...)` 형태는 전역 환경에 `f`라는 이름의 새로운 함수를 정의한다. 이는 개념적으로 다음과 유사한 과정을 거친다.



(setf (fdefinition 'f) #'(lambda (a) (block f b...)))



여기서 `setf`는 특정 위치의 값을 설정하는 매크로이며, `fdefinition 'f'`는 `f`라는 이름의 전역 함수 정의를 가리킨다. `#'`는 `function`이라는 특수 연산자의 축약형으로, 함수 객체 자체를 반환한다. 즉, `defun`은 `lambda`로 생성된 함수 객체를 `fdefinition`을 통해 해당 함수 이름과 연결하는 역할을 한다.

다음은 `defun`을 사용하여 숫자의 팩토리얼을 계산하는 함수의 예시이다. 재귀를 활용하여 정의할 수 있다.



(defun factorial (n)

(if (zerop n) 1 ; n이 0이면 1을 반환

(* n (factorial (1- n))))) ; n이 0이 아니면 n * (n-1의 팩토리얼)을 반환



꼬리 재귀 최적화를 지원하는 Common Lisp 구현에서는 다음과 같이 작성하여 스택 공간 사용을 줄일 수 있다.



(defun factorial (n &optional (acc 1))

(if (zerop n) acc

(factorial (1- n) (* acc n))))



반복문을 사용하여 팩토리얼을 구현할 수도 있다. Common Lisp의 `loop` 매크로를 사용한 예는 다음과 같다.



(defun factorial (n)

(loop for i from 1 to n

for fac = 1 then (* fac i)

finally (return fac)))


4. 4. 변수 스코프

리스프 계열 언어는 변수를 찾는 방식, 즉 스코프 규칙에 따라 동적 스코핑을 사용하는 언어와 정적 스코핑(어휘적 스코핑이라고도 함)을 사용하는 언어로 나눌 수 있다.

기본적으로 정적 스코핑을 사용하는 언어로는 클로저, 커먼 리스프, 스킴 등이 있다. 반면, newLISP, Picolisp 그리고 Emacs나 AutoCAD에 내장된 리스프는 동적 스코핑을 사용한다.

Emacs Lisp는 버전 24.1부터 동적 스코핑과 정적(어휘적) 스코핑을 모두 지원한다.

5. 주요 방언

리스프는 60년이 넘는 역사 동안 S-표현식 언어라는 핵심 주제를 바탕으로 다양한 변형을 낳았다. 각 방언은 여러 구현체를 가질 수 있는데, 예를 들어 커먼 리스프(Common Lisp)의 구현체는 12개가 넘는다.

1970년대에는 MIT의 프로젝트 맥(MAC)에서 개발된 맥리스프(MacLisp)와 Bolt Beranek & Newman 사와 제록스 팰러앨토 연구소가 함께 만든 인터리스프(Interlisp) 등이 널리 쓰였다. 이 외에도 이식성을 고려한 포터블 스텐다드 리스프(Portable Standard Lisp), UC 버클리의 프렌즈 리스프(Franz Lisp), MIT 인공지능 실험실의 제타리스프(Zetalisp) 등 다양한 변종들이 등장했다.

방언 간의 차이는 상당히 두드러질 수 있다. 예를 들어 함수 정의 방식 등에서 차이가 나타난다. (예: Common Lisp의 ''defun'', Scheme의 ''define'')[23] 하지만 표준화된 방언 내의 구현체들은 핵심 언어를 공유하며, 확장 기능 등에서 차이를 보인다.

현대 리스프 방언 중 가장 널리 알려진 것은 커먼 리스프스킴이다. 이들은 리스프 개발의 두 가지 주요 흐름을 대표하며, 서로 다른 설계 철학을 가지고 있다. 커먼 리스프는 다양한 기존 방언들의 기능을 통합하려는 시도에서 출발했으며, 스킴은 최소주의 철학을 바탕으로 설계되었다. 최근에는 JVM 환경 등에서 실행되는 클로저(Clojure)와 같이 함수형 프로그래밍 패러다임을 강조하는 새로운 방언들도 등장했다.[54]

또한, 리스프 방언들은 여러 응용 프로그램에서 스크립팅 언어로도 활발히 사용되고 있다. 리스프의 역사 속에서 여러 방언들이 공식적으로 표준화되기도 했다.[58]

5. 1. 커먼 리스프 (Common Lisp)

커먼 리스프(Common Lisp)는 1970년대와 1980년대에 존재했던 다양한 리스프 변종들의 기능을 통합하여 리스프 산업 표준을 만들려는 공동체의 노력으로 탄생했다. 당시 주요 변종으로는 MIT 프로젝트 맥(MAC)의 Maclisp, 제록스 팰러앨토 연구소 등의 인터리스프(Interlisp), 이식성을 강조한 포터블 스텐다드 리스프(Portable Standard Lisp), UC 버클리의 프렌즈 리스프(Franz Lisp), MIT 인공지능 실험실의 제타리스프(Zetalisp) 등이 있었다. 이러한 다양한 방언들을 아우르는 표준의 필요성이 제기되었고, 그 결과 1994년에 Common Lispeng의 ANSI 표준이 정해졌다.

Common Lispeng는 Maclisp의 후속 언어로 간주되며, Lisp Machine Lisp, Maclisp, NIL, S-1 Lisp, Spice Lisp, 그리고 스킴(Scheme) 등 여러 리스프 방언으로부터 영향을 받았다.[49] 특히, 리스프 머신 프로그래밍에 사용된 Lisp Machine Lispeng의 많은 기능을 포함하면서도, 일반적인 개인용 컴퓨터나 워크스테이션에서도 효율적으로 구현될 수 있도록 설계되었다. Common Lispeng는 범용 프로그래밍 언어로서, 다양한 내장 데이터 유형, 함수, 매크로 및 기타 언어 요소와 객체 시스템(Common Lisp Object System, CLOS)을 포함하는 방대한 언어 표준을 가지고 있다. 또한, 스킴으로부터 렉시컬 스코핑과 렉시컬 클로저와 같은 개념을 받아들였다.

Common Lispeng 구현은 다양한 환경을 지원한다. LLVM,[50] Java 가상 머신,[51] x86-64, PowerPC, Alpha, ARM, Motorola 68000, MIPS 등 여러 아키텍처를 대상으로 하며,[52] 윈도우, macOS, 리눅스, 솔라리스, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, Heroku 등 다양한 운영 체제에서 사용할 수 있다.[53]

Common Lispeng스킴과 함께 리스프 개발의 두 가지 주요 흐름을 대표하지만, 설계 철학에서 상당한 차이를 보인다. 스킴이 명확하고 단순한 의미론을 가진 미니멀리즘 디자인을 추구하는 반면, Common Lispeng는 풍부한 내장 기능과 표준을 제공하는 보다 실용적인 접근 방식을 취한다.

Common Lispeng의 중요한 특징 중 하나는 객체 지향 시스템인 CLOS(The Common Lisp Object System)이다. 이는 MIT의 Flavorseng 시스템의 영향을 받아 개발되었다. CLOSeng다중 상속과 다중 디스패치(멀티 메서드) 기능을 지원하며, 강력한 method combination|메서드 결합eng 시스템을 갖추고 있다. Common Lispeng는 공식적으로 표준화된 최초의 객체 지향 프로그래밍 언어이다.

5. 2. 스킴 (Scheme)

스킴(Scheme)은 MIT 인공지능 실험실의 Guy Lewis Steele Jr.와 Gerald Jay Sussman이 1975년에 처음 선보인 리스프의 한 갈래이다. 이후 MIT에서 컴퓨터 과학과 학생들을 가르치기 위해 다듬어졌으며, 이때 사용된 교재가 흔히 SICP 또는 위자드 북(Wizard book)이라고도 하는 《Structure and Interpretation of Computer Programs》이다.[101] 1990년에는 IEEE 표준으로도 제정되었다.

스킴은 Common Lisp와 함께 리스프 개발의 두 가지 주요 흐름을 대표하며, 서로 다른 설계 철학을 보여준다. 스킴은 최소주의(minimalism) 철학을 바탕으로, 매우 명확하고 단순한 의미론과 적은 수의 표현 방식을 갖도록 설계되었다. 이는 Common Lisp보다 약 10년 먼저 설계된 영향도 있으며, 표준 기능의 수는 적지만 정적 스코프(lexical scoping), 꼬리 재귀 최적화(tail-call optimization), 그리고 전체 지속(continuation)과 같은 중요한 구현 기능을 요구한다는 특징이 있다. 이러한 특징 덕분에 명령형, 함수형, 메시지 전달 등 다양한 프로그래밍 패러다임을 효과적으로 표현할 수 있다.

스킴은 일련의 표준 문서("Revisedn Report on the Algorithmic Language Scheme")와 Scheme Requests for Implementation(SRFI)을 통해 꾸준히 발전하고 있다. 또한, GIMP 이미지 편집기의 'Script-fu'( SIOD나 TinyScheme 기반)[56]나 LilyPond 악보 조판 프로그램 등 여러 응용 프로그램에서 스크립팅 언어로 널리 사용되고 있다. 스킴 인터프리터는 크기가 작을 수 있어 임베디드 환경에 특히 적합하다.

5. 3. 클로저 (Clojure)

Clojure는 리스프 방언의 하나로, 주로 Java 가상 머신(JVM)과 Common Language Runtime(CLR), Python VM, Ruby VM YARV 환경에서 실행되도록 설계되었다. 또한 JavaScript로 컴파일될 수도 있다. Clojure는 실용적인 범용 프로그래밍 언어를 목표로 하며, 함수형 프로그래밍 언어인 Haskell로부터 상당한 영향을 받아 데이터의 불변성을 매우 강조하는 특징을 가진다.[54]

Clojure는 Java 프레임워크 및 라이브러리를 직접 활용할 수 있다는 장점이 있다. 선택적으로 타입 힌트나 타입 추론 기능을 사용하여 리플렉션 없이 Java 코드를 호출하고 빠른 연산을 수행할 수 있도록 지원한다. 하지만 다른 리스프 방언들과의 하위 호환성은 고려하지 않고 설계되었다.[55]

5. 4. 기타 방언

리스프 방언은 많은 응용 프로그램에서 스크립팅 언어로 사용된다. 대표적인 예로는 Emacs 편집기의 Emacs Lisp, AutoCAD의 AutoLISP 및 이후 버전인 Visual LISP, Audacity의 Nyquist, LilyPond의 Scheme 등이 있다. Scheme 인터프리터는 크기가 작아 임베디드 스크립팅에 특히 적합하며, GIMP 이미지 편집기에는 SIOD와 TinyScheme이 "Script-fu"라는 이름으로 내장되었다.[56] 또한, Emacs Lisp를 기반으로 한 LIBREP는 Sawfish 윈도우 매니저에 사용되었다.[57]

이 외에도 다양한 리스프 방언들이 존재한다.

방언 이름간략 설명
AutoLISP / Visual LISPAutoCAD 제품의 사용자 정의를 위한 언어.
Cambridge LISP원래 IBM메인프레임에서 구현되었으며, 메타콤코에 의해 Amiga용으로 발표되었다.
ClojureJava 가상 머신 위에서 동작하는 리스프. 멀티스레드 프로그램 개발을 용이하게 하는 범용 언어. Haskell의 영향을 받아 불변성을 강조한다.[54] 다른 리스프 방언과의 하위 호환성은 고려되지 않았다.[55]
ELisp오래된 리스프 구현 중 하나로, Emacs Lisp와는 다르다.
Emacs LispGNU Emacs 텍스트 편집기의 확장 언어.
Franz LISP원래 캘리포니아 대학교 버클리의 프로젝트였으나, 나중에 Franz, Inc.로 이전되었다.
InterLispBBN 테크놀로지스에서 개발 (초기 명칭: BBN LISP). 이후 개발 그룹이 제록스의 팔로 알토 연구소로 이동하면서 InterLisp로 개명되었고, 제록스의 LISP 머신에도 InterLisp-D로 채택되었다. 강력한 대화형 개발 도구가 특징이다. 더 작은 버전인 "InterLISP 65"는 Atari의 6502 기반 컴퓨터용으로 발표되었다.
KLISP1967년 나카니시 마사카즈가 TOSBAC-3400 위에서 개발하여, 일본의 리스프 연구와 교육에 기여했다.
LISP I / LISP 1.5MIT에서 개발된 매카시의 오리지널 버전.
Lispkit LISP순수 함수형 언어 방언으로, SECD 머신 위에 구현되었다. 함수형 언어 개념의 실험용 테스트베드로 사용되었다.
MACLispMIT의 프로젝트 MAC (애플의 매킨토시와는 무관)을 위해 개발된 리스프의 직계 후손.
MockLispGosling Emacs (Unipress Emacs) 에디터의 확장 언어. 리스트가 없는 리스프.
Oak LISPScheme 기반의 객체 지향 언어.
RPL"Reverse Polish LISP"(후위 표기법식 리스프)라는 이름의 언어. 후위 표기법, 스택 지향 방식을 채택하는 등 Forth의 영향도 크다. 휴렛 팩커드사의 공학용 계산기 내장을 상정하고 개발되었다.
Scheme동적 스코프가 아닌 정적 스코프에 기초하여 재설계된 리스프. 미니멀한 디자인이 특징이다.
SKILL케이던스 디자인 시스템즈사의 많은 EDA 제품에서 사용된다.
ZetaLispLISP 머신을 위해 사용되었으며, MACLisp의 직계 후손.
순수 LISP초순환 평가기를 기술할 수 있을 정도로 기능을 축약한 작은 서브셋 방언. 이론적으로 제시되었으나 실제 구현도 가능하다.
xyzzy윈도우에서 작동하는 편집기. 매크로 언어로 xyzzy Lisp를 구현하고 있다.


6. 응용 분야

리스프는 특정 분야에 국한되지 않고 다양한 영역에서 활용되어 온 프로그래밍 언어이다. 특히 인공 지능 연구 초창기부터 중요한 역할을 담당했으며, Emacs나 AutoCAD와 같은 유명 소프트웨어에서는 사용자 기능을 확장하는 스크립트 언어로도 널리 사용되었다. 이처럼 리스프는 학술 연구부터 실용적인 응용 프로그램 개발에 이르기까지 폭넓은 영향력을 보여주었다.

6. 1. 인공지능

리스프는 시작부터 인공 지능 연구 커뮤니티와 밀접한 관계를 맺었다. 특히 PDP-10[21] 시스템 환경에서 많이 활용되었다. 유명한 초기 인공지능 시스템인 SHRDLU에 사용된 언어 마이크로 플래너는 리스프를 기반으로 구현되었다.

1970년대에 인공지능 연구가 상업적인 결과물을 내놓기 시작하면서, 기존 리스프 시스템의 성능 문제가 점차 중요하게 부각되었다. 이에 따라 프로그래머들은 리스프 구현에 사용되는 다양한 기술과 선택이 실제 성능에 어떤 영향을 미치는지 깊이 이해하고 고려해야만 했다.[22]

6. 2. 임베디드 스크립팅 언어

리스프는 특정 응용 프로그램의 기능을 확장하기 위한 스크립트 언어로도 널리 사용된다. 대표적인 예로는 Emacs 편집기에서 사용되는 Elisp가 있으며, 이를 통해 사용자는 편집기의 기능을 직접 확장하고 맞춤 설정할 수 있다. 또한, 설계 시스템(Computer-Aided Design, 줄여서 CAD) 분야에서는 AutoCAD 시스템에서 AutoLisp가 사용되어 설계 작업을 자동화하거나 새로운 기능을 추가하는 데 활용된다. 이 외에도 Scheme을 기반으로 한 운영체제 셸 언어(scsch 등)도 리스프가 임베디드 스크립팅 환경에서 사용된 사례 중 하나이다.

7. Lisp 머신

1968년에 LISP영어로 구현된 REDUCE영어[99]나 Macsyma영어와 같은 수식 처리 시스템이 등장하면서 LISP영어의 수요가 높아졌다. 이러한 시스템의 인기는 LISP영어를 더 빠르게 처리할 수 있는 고성능 시스템에 대한 요구로 이어졌고, 이는 LISP영어 실행에 최적화된 전용 하드웨어인 LISP영어 머신 개발의 중요한 동기 중 하나가 되었다. LISP영어 머신은 태그 아키텍처나 하드웨어 스택과 같이 LISP영어 언어의 특징에 맞는 하드웨어 구조를 갖추고 있었다. 이를 통해 타입 확인(디스패치), 함수 호출, 가비지 컬렉션과 같은 작업을 하드웨어 수준에서 가속하여 LISP영어 프로그램의 실행 속도를 크게 향상시켰다.

8. 객체 지향 시스템

리스프 위에서, 리스프와 함께, 또는 리스프 내부에 다양한 객체 시스템과 모델이 구축되었다. 주요 시스템은 다음과 같다.

시스템설명
공통 리스프 객체 시스템 (CLOS)ANSI 공통 리스프 표준의 핵심 부분이다. New Flavors영어와 CommonLoops에서 파생되었으며, 1994년 ANSI X3J13에 의해 표준화된 최초의 객체 지향 프로그래밍 언어이다. 다중 상속, 다중 디스패치 (멀티 메서드), 강력한 메서드 결합 시스템을 특징으로 한다.
FlavorsMIT에서 개발된 초기 객체 시스템이다. 이후 Symbolics에서 New Flavors영어로 발전했으며, CLOS의 기반이 되었다.
오브젝트 리스프 (ObjectLisp)LMI와 초기 버전의 매킨토시 커먼 리스프에서 사용되었다.
LOOPS 및 CommonLoops각각 Lisp Object-Oriented Programming System과 Common Lisp Object-Oriented Programming System의 약자이다. CommonLoops는 CLOS 개발에 영향을 주었다.
KRKnowledge Representation영어의 약자로, 제약 만족 기반 객체 시스템이다. 공통 리스프용 GUI 라이브러리인 Garnet 개발을 지원했다.
지식 공학 환경 (KEE)UNITS영어라는 객체 시스템을 사용했으며, 이를 추론 엔진 및 이유 유지 시스템(ATMS)과 통합했다.



공통 리스프를 포함한 리스프는 CLOS를 통해 공식적으로 표준화된 최초의 객체 지향 프로그래밍 언어가 되었다.

9. 운영 체제

리스프를 기반으로 하거나 리스프로 작성된 언어 기반 시스템을 포함한 여러 운영 체제가 있다.[75] 주요 운영 체제는 다음과 같다.


  • Genera: Symbolics에서 제작했으며, 나중에 Open Genera로 이름이 변경되었다.[76]
  • Medley: Interlisp로 작성되었으며, 원래 Xerox의 후기 Star 워크스테이션에서 실행되던 그래픽 운영 체제이다.[77][78]
  • Mezzano[79]
  • Interim[80][81]
  • ChrysaLisp: Tao Systems의 TAOS 개발자가 제작했다.[82]
  • GNU Guix 시스템: GNU/Linux용 운영 체제이다.

참조

[1] 웹사이트 Introduction http://julia.readthe[...] Read the Docs 2016-12-10
[2] 웹사이트 Wolfram Language Q&A https://www.wolfram.[...] Wolfram Research 2016-12-10
[3] 서적 Milestones in computer science and information technology https://books.google[...] Greenwood Publishing Group
[4] 웹사이트 SICP: Foreword http://mitpress.mit.[...]
[5] 웹사이트 Conclusions http://www-formal.st[...] 2014-06-04
[6] 서적 Common Lisp: the language Digital Press 1990
[7] 웹사이트 "The Racket Manifesto" https://www2.ccs.neu[...] 2015
[8] 웹사이트 Clojure - Differences with other Lisps https://clojure.org/[...] 2022-10-27
[9] 웹사이트 The Art of the Interpreter, or the Modularity Complex (Parts Zero, One, and Two), Part Zero, P. 4 https://dspace.mit.e[...] MIT Libraries 1978-05
[10] 서적 Gödel, Escher, Bach: An Eternal Golden Braid (Twentieth Anniversary Edition) https://books.google[...] Basic Books
[11] 웹사이트 Revenge of the Nerds http://www.paulgraha[...] 2013-03-14
[12] 서적 Influential Programming Languages, Part 4: Lisp http://www.informit.[...] 2011-01-12
[13] 서적 The Art of Lisp Programming Springer Science & Business Media 2012-12-06
[14] 웹사이트 Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I http://www-formal.st[...] 2006-10-13
[15] 서적 MLISP Users Manual http://www.softwarep[...] 2006-10-13
[16] 웹사이트 History of Lisp: Artificial Intelligence Laboratory http://jmc.stanford.[...] 1979-02-12
[17] conference Early LISP history (1956–1959) Association for Computing Machinery 1984-08-06
[18] 웹사이트 LISP prehistory - Summer 1956 through Summer 1958 http://www-formal.st[...] 2010-03-14
[19] 웹사이트 AI Memo 39-The new compiler ftp://publications.a[...] 2019-03-18
[20] 서적 LISP 1.5 Programmer's Manual http://www.softwarep[...]
[21] 뉴스그룹 The History of TOPS or Life in the Fast ACs http://groups.google[...] 1990-10-18
[22] 간행물 The evolution of Lisp http://dl.acm.org/do[...] ACM 2022-07-25
[23] 문서 Common Lisp: (defun f (x) x)
Scheme: (define f (lambda (x) x)) or (define (f x) x)

[24] 서적 LISP I Programmers Manual http://history.siam.[...] Artificial Intelligence Group, [[M.I.T. Computation Center]] and Research Laboratory 1960-03
[25] 서적 LISP 1.5 Programmer's Manual http://www.softwarep[...] MIT Press
[26] 서적 Stanford LISP 1.6 Manual http://www.softwarep[...]
[27] 웹사이트 Maclisp Reference Manual http://zane.brouhaha[...] 1979-03-03
[28] 서적 InterLisp Reference Manual http://www.bitsavers[...] 2006-08-19
[29] 문서 Outils de generation d'interfaces : etat de l'art et classification by H. El Mrabet https://hal.archives[...]
[30] 웹사이트 Scheme: An Interpreter for Extended Lambda Calculus https://dspace.mit.e[...] 1975-12
[31] 서적 Common Lisp the Language Digital Press
[32] 웹사이트 History: Where did Lisp come from? https://www.cs.cmu.e[...] 1996-02-20
[33] 웹사이트 ISO/IEC 13816:1997 http://www.iso.org/i[...] Iso.org 2007-10-01
[34] 웹사이트 ISO/IEC 13816:2007 http://www.iso.org/i[...] Iso.org 2013-10-30
[35] 웹사이트 X3J13 Charter http://www.nhplace.c[...]
[36] 웹사이트 The Road To Lisp Survey http://wiki.alu.org/[...] 2006-10-13
[37] 웹사이트 Trends for the Future http://www.faqs.org/[...] Faqs.org 2013-11-15
[38] 웹사이트 Common Lisp Implementations: A Survey http://common-lisp.n[...] 2012-04-04
[39] 웹사이트 Planet Lisp https://planet.lisp.[...] 2023-10-12
[40] 웹사이트 LispForum https://lispforum.co[...] 2023-10-12
[41] 웹사이트 Lispjobs https://lispjobs.wor[...] 2023-10-12
[42] 웹사이트 Quicklisp https://www.quicklis[...] 2023-10-12
[43] 웹사이트 LISP50@OOPSLA http://www.lisp50.or[...] Lisp50.org 2013-11-15
[44] 문서 Documents: Standards: R5RS http://www.schemers.[...]
[45] 뉴스 Why MIT now uses python instead of scheme for its undergraduate CS program http://cemerick.com/[...] 2009-03-24
[46] 뉴스 The End of an Era http://mitadmissions[...] 2008-01-08
[47] 웹사이트 MIT EECS Undergraduate Programs https://www.eecs.mit[...] MIT Electrical Engineering & Computer Science 2018-12-31
[48] 웹사이트 MITx introductory Python course hits 1.2 million enrollments https://www.eecs.mit[...] MIT Electrical Engineering & Computer Science 2018-12-31
[49] 문서 Chapter 1.1.2, History, ANSI CL Standard
[50] 문서 Clasp is a Common Lisp implementation that interoperates with C++ and uses LLVM for [[just-in-time compilation]] (JIT) to native code. https://www.cliki.ne[...]
[51] 문서 "Armed Bear Common Lisp (ABCL) is a full implementation of the Common Lisp language featuring both an interpreter and a compiler, running in the JVM" https://common-lisp.[...]
[52] Webarchive Common Lisp Implementations: A Survey https://common-lisp.[...] 2018-06-22
[53] 문서 Comparison of actively developed Common Lisp implementations https://www.cliki.ne[...]
[54] 문서 An In-Depth Look at Clojure Collections http://www.infoq.com[...] 2012-06-24
[55] 웹사이트 Clojure rational https://clojure.org/[...] 2019-08-27
[56] 문서 Script-fu In GIMP 2.4 http://www.gimp.org/[...] 2009-10-29
[57] 문서 librep http://sawfish.wikia[...] 2009-10-29
[58] 웹사이트 IEEE Scheme https://standards.ie[...] 2019-08-27
[59] 웹사이트 What Made Lisp Different http://paulgraham.co[...] 2002-05
[60] 웹사이트 LISP prehistory - Summer 1956 through Summer 1958. http://www-formal.st[...]
[61] 웹사이트 Meaning of 'Object-Oriented Programming' According to Dr. Alan Kay http://userpage.fu-b[...] 2003-07-23
[62] 간행물 A Real-Time Garbage Collector Based on the Lifetimes of Objects http://web.media.mit[...] 1983-06
[63] 간행물 The Humble Programmer (EWD 340) http://www.cs.utexas[...]
[64] 웹사이트 A Look at Clojure and the Lisp Resurgence https://www.linkedin[...]
[65] 웹사이트 The Jargon File - Lisp http://www.catb.org/[...] 2006-10-13
[66] 서적 Concepts of Programming Languages https://www.pearson.[...] Addison-Wesley 2012
[67] 문서 NB: a so-called "dotted list" is only one kind of "improper list". The other kind is the "circular list" where the cons cells form a loop. Typically this is represented using #n=(...) to represent the target cons cell that will have multiple references, and #n# is used to refer to this cons. For instance, (#1=(a b) . #1#) would normally be printed as ((a b) a b) (without circular structure printing enabled), but makes the reuse of the cons cell clear. #1=(a . #1#) cannot normally be printed as it is circular, although (a...) is sometimes displayed, the CDR of the cons cell defined by #1= is itself.
[68] 웹사이트 CSE 341: Scheme: Quote, Quasiquote, and Metaprogramming http://www.cs.washin[...] Cs.washington.edu 1999-02-22
[69] 문서 Quasiquotation in Lisp http://repository.re[...] 2013-06-03
[70] 문서 Time of Evaluation - Common Lisp Extensions https://www.gnu.org/[...]
[71] 웹사이트 3.2.2.3 Semantic Constraints http://www.lispworks[...]
[72] 간행물 4.3. Control Abstraction (Recursion vs. Iteration) http://www.cs.umd.ed[...] 1993-08
[73] 문서 pg 17 of Bobrow 1986
[74] 문서 Veitch, p 108, 1988
[75] 뉴스 The wild world of non-C operating systems https://www.theregis[...] The Register 2024-04-04
[76] 웹사이트 Symbolics Open Genera 2.0 https://archive.org/[...] 2022-02-02
[77] 웹사이트 Interlisp.org Project https://interlisp.or[...] 2022-02-02
[78] 웹사이트 Interlisp Medley https://github.com/I[...] 2022-02-02
[79] 웹사이트 Mezzano https://github.com/f[...] 2022-02-02
[80] 웹사이트 Interim http://interim-os.co[...] 2022-02-02
[81] 웹사이트 Interim https://github.com/m[...] 2022-02-02
[82] 웹사이트 ChrysaLisp https://github.com/v[...] 2022-02-02
[83] 웹사이트 UK micro pioneer Chris Shelton: The mind behind the Nascom 1 https://www.theregis[...] 2022-02-02
[84] 웹사이트 The implementation of LISP https://www-formal.s[...] 2024-04-07
[85] 웹사이트 McCarthy et al. LISP I Programmer's Manual. — Software Preservation Group https://www.software[...] 2024-04-07
[86] 웹사이트 RECURSIVE FUNCTIONS OF SYMBOLIC EXPRESSIONS AND THEIR COMPUTATION BY MACHINE (Part I) (12-May-1998) https://www-formal.s[...] 2024-04-07
[87] 웹사이트 SICP: 序文 http://sicp.iijlab.n[...] 2015-10-20
[88] 웹사이트 技術野郎の復讐 http://practical-sch[...] 2015-10-20
[89] 웹사이트 From LISP 1 to LISP 1.5 https://www-formal.s[...] 2024-04-07
[90] 간행물 MACRO definitions for LISP https://hdl.handle.n[...]
[91] 간행물 Scheme: An Interpreter for Extended Lambda Calculus https://hdl.handle.n[...]
[92] 학술지 Scheme: A interpreter for extended lambda calculus https://doi.org/10.1[...] Springer
[93] 서적 ANSI Common Lisp ピアソン・エデュケーション 2002-09-01
[94] 문서 "c ontent of a ddress part of r egister"
[95] 문서 "c ontent of d ecrement part of r egister"
[96] 웹사이트 McCarthy et al. LISP 1.5 Programmer's Manual. — Software Preservation Group https://www.software[...] 2024-04-07
[97] 웹사이트 Berkeley and Bobrow, editors. The Programming Language LISP: Its Operation and Applications. — Software Preservation Group https://www.software[...] 2024-04-07
[98] 웹사이트 The History of TOPS or Life in the Fast ACs https://groups.googl[...] 2016-10-06
[99] 웹사이트 REDUCE: The First Forty Years http://www.reduce-al[...]
[100] 학술지 기호로 나타낸 재귀 함수와 기계를 이용한 계산 http://www-formal.st[...] 2024-10-18
[101] 서적 Structure and Interpretation of Computer Programs https://mitp-content[...] MIT Press 2024-10-18



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com