커먼 리스프
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
커먼 리스프(Common Lisp)는 1980년대 초 여러 리스프 방언의 호환성 문제를 해결하기 위해 개발된 리스프 프로그래밍 언어의 한 방언이다. 코드와 데이터 구조를 모두 S-표현식으로 표현하며, 함수와 매크로 호출은 리스트 형식으로 작성된다. 커먼 리스프는 렉시컬 및 동적 스코프를 모두 지원하고, 조건 시스템을 통한 예외 처리, 객체 지향 프로그래밍을 위한 커먼 리스프 객체 시스템(CLOS)을 제공한다. 인터프리터와 컴파일러를 모두 지원하며, 다양한 자료형과 데이터 구조를 갖추고 있다. 여러 구현체가 존재하며, 연구, 프로토타입 개발, 상업용 애플리케이션 등 다양한 분야에서 활용된다.
더 읽어볼만한 페이지
- 1984년 개발된 프로그래밍 언어 - MSX 베이직
MSX BASIC은 MSX 컴퓨터를 위한 BASIC 프로그래밍 언어 및 인터프리터로, 다양한 버전과 확장을 통해 텍스트, 그래픽, 하드웨어 스프라이트, 인터럽트 기능 등을 지원하며, MSX 고유 기능을 활용하는 애드온 모듈 개발도 이루어졌다. - 1984년 개발된 프로그래밍 언어 - 비주얼 폭스프로
비주얼 폭스프로는 xBase 언어군에 속하는 절차적 프로그래밍 언어이자 데이터베이스 관리 시스템으로, dBase를 기반으로 관계형 데이터베이스 엔진과 통합되어 SQL 쿼리 및 데이터 조작을 지원하며, 마이크로소프트 개발 중단 후 커뮤니티 주도의 개발이 진행되었다. - 리스프 - AI 겨울
AI 겨울은 인공지능 연구에 대한 자금 지원과 관심이 크게 감소했던 시기를 가리키며, 기계 번역의 어려움, 신경망의 한계, 전문가 시스템 문제, 5세대 컴퓨터 실패 등의 요인으로 여러 차례 침체기를 겪었으나, 2000년대 이후 음성 및 이미지 인식 분야에서 성과를 거두며 부흥했고, 2022년 이후 대규모 언어 모델 등장으로 관심과 투자가 폭발적으로 증가했다. - 리스프 - 리스프 머신
리스프 머신은 Lisp 언어의 효율적인 실행을 위해 설계된 컴퓨터 시스템으로, 인공지능 연구와 컴퓨터 그래픽스 분야에 영향을 미쳤으나 상업적 성공은 거두지 못했고, 기술적 유산은 현재까지 연구되고 있다. - 리스프 프로그래밍 언어 계열 - 클로저 (프로그래밍 언어)
클로저는 리치 히키가 개발한 JVM 기반의 함수형 프로그래밍 언어로, 자바와의 호환성을 특징으로 하며 불변 데이터 구조와 STM을 활용한 동시성 관리, 그리고 REPL 환경, 매크로 시스템 등의 기능을 제공한다. - 리스프 프로그래밍 언어 계열 - 딜런 (프로그래밍 언어)
딜런은 애플에서 개발되어 오픈 소스화된 동적 프로그래밍 언어로, Lisp의 영향, 다중 상속, 제네릭 함수 등의 특징과 높은 확장성을 제공한다.
커먼 리스프 - [IT 관련 정보]에 관한 문서 | |
---|---|
기본 정보 | |
종류 | 프로그래밍 언어 표준 |
계열 | 리스프 |
패러다임 | 다중 패러다임: 절차적 함수형 객체 지향 메타 반사 제네릭 |
세대 | 3세대 |
발표 | 1984년 |
ANSI 표준 | 1994년 |
설계자 | 스콧 팔만 리처드 P. 가브리엘 데이비드 A. 문 켄트 피트먼 가이 스틸 댄 와인렙 |
개발자 | ANSI X3J13 위원회 |
표준 참조 | Common Lisp HyperSpec |
타이핑 | 동적, 강타입 |
스코프 | 어휘적, 선택적으로 동적 |
네임스페이스 스타일 | 리스프-2 |
구현체 | Allegro CL ABCL Clasp CLISP Clozure CL CMUCL ECL GCL LispWorks Scieneer CL SBCL Symbolics Common Lisp |
방언 | CLtL1, CLtL2, ANSI Common Lisp |
영향을 준 언어 | 리스프 Lisp Machine Lisp Maclisp Scheme Interlisp |
영향을 받은 언어 | Clojure Dylan Emacs Lisp EuLisp ISLISP *Lisp AutoLisp Julia Moose R SKILL SubL |
운영 체제 | 크로스 플랫폼 |
웹사이트 | common-lisp.net |
파일 확장자 | .lisp, .lsp, .l, .cl, .fasl |
2. 역사
1980년대 초, 여러 리스프 방언들이 난립하면서 호환성 문제가 발생하자, 이를 해결하기 위해 커먼 리스프 개발이 시작되었다. 1981년, ARPA 관리자 밥 엥겔모어의 주도로 단일 커뮤니티 표준 리스프 방언을 개발하려는 시도가 있었다.[7] 초기 언어 설계는 대부분 전자 메일을 통해 이루어졌다.[8][9] 1982년, 가이 L. 스틸 주니어는 1982년 ACM 리스프 및 함수형 프로그래밍 심포지엄에서 커먼 리스프에 대한 첫 번째 개요를 발표했다.[10]
커먼 리스프는 리스프의 방언으로, 코드와 데이터 구조를 모두 S-표현식으로 나타낸다. 함수와 매크로 호출은 이름을 제일 처음에 쓴 리스트 형식으로 작성된다.
1984년, ''Common Lisp the Language'' (CLtL1) 초판이 출판되었다. 1990년에 출판된 제2판(CLtL2)은 ANSI 커먼 리스프 표준화 과정에서 이루어진 많은 언어 변경 사항을 통합했는데, 확장된 LOOP 구문, 커먼 리스프 객체 시스템, 오류 처리를 위한 조건 시스템, 예쁜 프린터 인터페이스 등이 그것이다. 그러나 CLtL2는 최종 ANSI 커먼 리스프 표준을 설명하지 않으므로 ANSI 커먼 리스프의 문서는 아니다. 최종 ANSI 커먼 리스프 표준은 1994년에 출판되었다. 그 이후로 표준에 대한 업데이트는 발표되지 않았지만, 커먼 리스프에 대한 다양한 확장 및 개선 사항(예: 유니코드, 동시성, CLOS 기반 IO)은 구현 및 라이브러리를 통해 제공되고 있다.
3. 문법
평가 순서는 "왼쪽에서 오른쪽", "안쪽에서 바깥쪽" 모델을 따른다. 예를 들어 `(F A1 A2)`와 같은 S식에서 `F`가 함수라면, 인자 A1, A2를 왼쪽에서 오른쪽으로 순서대로 평가하고, 마지막으로 F에 그 인자를 전달한다. `F`가 매크로라면, 먼저 매크로를 전개한다.[1]
3. 1. 예제
커먼 리스프는 S-표현식으로 코드와 데이터 구조를 모두 나타내는 리스프의 방언이다. 함수, 매크로 호출, 특수 형식은 연산자 이름을 먼저 쓰는 목록으로 작성된다.
```lisp
(+ 2 2) ; 2와 2를 더하여 4를 반환한다. 함수의 이름은 '+'이다. 리스프에는 연산자 자체가 없다.
```
```lisp
(defvar *x*) ; 변수 *x*가 존재하도록 한다.
; 값을 부여하지 않는다. 별표는
; 이름의 일부이며, 관례적으로 특수(전역) 변수를 나타낸다.
; 또한, 심볼 *x*는 이후의 바인딩이
; 어휘적이기보다는 동적이라는 속성을 갖는다.
(setf *x* 42.1) ; 변수 *x*를 부동 소수점 값 42.1로 설정한다.
```
```lisp
;; 숫자를 제곱하는 함수를 정의한다:
(defun square (x)
(* x x))
```
```lisp
;; 함수를 실행한다:
(square 3) ; 9를 반환한다.
```
```lisp
;; 'let' 구조는 지역 변수를 위한 범위를 만든다. 여기서
;; 변수 'a'는 6에 바인딩되고 변수 'b'는
;; 4에 바인딩된다. 'let' 안에는 마지막으로 계산된 값이 반환되는 '본문'이 있다.
;; 여기서는 a와 b를 더한 결과가 'let' 표현식에서 반환된다.
;; 변수 a와 b는 어휘적 범위를 가지며, 심볼이
;; 특수 변수로 표시되지 않는 한 (예: 이전 DEFVAR에 의해).
(let ((a 6)
(b 4))
(+ a b)) ; 10을 반환한다.
```
다음 프로그램은 생일이 모두 다를 확률이 50% 미만인 최소 인원수를 계산한다. (생일 문제, 여기서 1명일 경우 확률은 당연히 100%이고, 2명일 경우 364/365, 등등이다.) 답은 23명이다.
커먼 리스프에서는 관례적으로 상수는 + 문자로 묶는다.
```lisp
(defconstant +year-size+ 365)
(defun birthday-paradox (probability number-of-people)
(let ((new-probability (* (/ (- +year-size+ number-of-people)
+year-size+)
probability)))
(if (< new-probability 0.5)
(1+ number-of-people)
(birthday-paradox new-probability (1+ number-of-people)))))
```
REPL(Read Eval Print Loop, 읽기-평가-출력 루프)을 사용하여 예시 함수를 호출한다.
```text
CL-USER > (birthday-paradox 1.0 1)
23
```
```lisp
(defclass person ()
((name :initarg :name :accessor person-name)
(age :initarg :age :accessor person-age))
(:documentation "NAME과 AGE 슬롯을 가진 PERSON 클래스."))
(defmethod display ((object person) stream)
"출력 스트림에 PERSON 객체를 표시한다."
(with-slots (name age) object
(format stream "~a (~a)" name age)))
(defparameter *group*
(list (make-instance 'person :name "Bob" :age 33)
(make-instance 'person :name "Chris" :age 16)
(make-instance 'person :name "Ash" :age 23))
"PERSON 객체의 리스트.")
(dolist (person (sort (copy-list *group*)
#'>
:key #'person-age))
(display person *standard-output*)
(terpri))
```
나이가 내림차순으로 세 개의 이름을 출력한다.
```text
Bob (33)
Ash (23)
Chris (16)
```
`LOOP` 매크로의 사용법은 다음과 같다:
```lisp
(defun power (x n)
(loop with result = 1
while (plusp n)
when (oddp n) do (setf result (* result x))
do (setf x (* x x)
n (truncate n 2))
finally (return result)))
```
사용 예시:
```lisp
CL-USER > (power 2 200)
1606938044258990275541962092341162602522202993782792835301376
```
내장된 지수 연산과 비교:
```lisp
CL-USER > (= (expt 2 200) (power 2 200))
T
```
`WITH-OPEN-FILE`은 파일을 열고 스트림을 제공하는 매크로이다. 폼이 반환될 때 파일은 자동으로 닫힌다. `FUNCALL`은 함수 객체를 호출한다. `LOOP`는 술어와 일치하는 모든 행을 수집한다.
```lisp
(defun list-matching-lines (file predicate)
"파일 내에서, 행에 적용된 술어가 T를 반환하는 행의 목록을 반환한다."
(with-open-file (stream file)
(loop for line = (read-line stream nil nil)
while line
when (funcall predicate line)
collect it)))
```
`AVAILABLE-SHELLS` 함수는 위의 `LIST-MATCHING-LINES` 함수를 파일 경로와 익명 함수를 술어로 호출한다. 술어는 셸의 파일 경로를 반환하거나, 문자열이 셸의 파일명이 아닌 경우 `NIL`을 반환한다.
```lisp
(defun available-shells (&optional (file #p"/etc/shells"))
(list-matching-lines
file
(lambda (line)
(and (plusp (length line))
(char= (char line 0) #\/)
(pathname
(string-right-trim '(#\space #\tab) line))))))
```
예시 결과 (Mac OS X 10.6에서):
```lisp
CL-USER > (available-shells)
(#P"/bin/bash" #P"/bin/csh" #P"/bin/ksh" #P"/bin/sh" #P"/bin/tcsh" #P"/bin/zsh")
4. 데이터 타입
커먼 리스프는 다양한 자료형을 지원한다. 커먼 리스프의 타입 시스템은 계층적이다. 타입은 '''deftype'''을 사용하여 정의되며, ''supertype'', ''subtype''이라는 개념을 가진다. 모든 ''type''은 ''supertype''으로서 ''t''(다른 언어에서의 ''true'' 또는 ''Object'')를 가진다. 따라서 모든 객체는 타입 ''t''의 인스턴스이다. 한편, 타입 ''nil''은 어떤 객체도 그 인스턴스가 될 수 없는 타입이다.[67]
타입에는 ''built-in'' 타입과 그렇지 않은 것이 있다. ''built-in'' 타입은 [http://www.lispworks.com/documentation/HyperSpec/Body/04_bc.htm 정수, 부동 소수점, 복소수, 문자 등]과 같은 (다른 언어에서 말하는) 원시적인 타입에 배열이나 스트림 등 내장된 타입을 합한 것이다. ''built-in''이 아닌 타입에는 구조체, 클래스 등이 있다. 이처럼 타입 시스템은 클래스 및 객체 시스템과 연속적으로 융합되어 있다.
타입은 ''type specifier''라는 기술 방식으로 참조되며, 이는 종종 ''typespec''으로 줄여서 사용된다. ''typespec''을 사용하여 논의할 때, ''built-in''과는 직교하는 개념으로, ''Atomic Type'' 대 ''Compound Type''이라는 개념이 있다. [http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#compound_type_specifier Compound type]은 대략적으로, 인수를 취할 수 있는 타입이다. 예를 들어, (array fixnum (5 * 7))
은 데이터 내용이 모두 정수형이고, 크기가 차원별로 "5, 가변 길이, 7"인 배열을 나타낸다.[68]
''Compound Type''에서는 원래의 타입에 맞춰 특정 단일 변수 함수를 타입 판정에 사용할 수도 있다.
하지만 Common Lisp에는 Haskell과 같은 타입 변수의 개념은 없다. 위의 ''array''의 예에서 인수는 변수가 아닌 상수로 처리되기 때문이다.
4. 1. 스칼라 타입
정수, 비율, 부동 소수점 숫자, 복소수를 포함한다.[11] 커먼 리스프는 bignum을 사용하여 임의의 크기와 정밀도의 숫자 값을 표현한다. 비율 형식은 분수를 정확하게 표현하며, 커먼 리스프는 필요에 따라 이러한 형식 간에 숫자 값을 자동 변환한다.문자 형식은 ASCII 문자로 제한되지 않고, 대부분의 최신 구현은 유니코드 문자를 허용한다.[12]
심볼 형식은 리스프 언어에 공통적이다. 심볼은 이름, 값, 함수, 프로퍼티 목록 및 패키지와 같은 여러 부분으로 구성된 고유한 명명된 데이터 객체이다. 이 중에서 값 셀과 함수 셀이 가장 중요하며, 리스프의 심볼은 다른 언어의 식별자와 유사하게 변수의 값을 저장하는 데 자주 사용되지만, 이 외에도 많은 용도로 사용된다. 일반적으로 심볼이 평가되면 해당 값이 반환된다. 일부 심볼은 자기 자신으로 평가된다. 예를 들어, 키워드 패키지의 모든 심볼은 자기 평가적이다. 커먼 리스프의 참/거짓 값은 자기 평가적 심볼 T와 NIL로 표현된다. 커먼 리스프는 '패키지'라고 하는 심볼에 대한 네임스페이스를 가지고 있다.
4. 2. 데이터 구조
커먼 리스프의 '''시퀀스형'''에는 리스트, 벡터, 비트 벡터, 문자열이 있다. `map`이나 `reduce`와 같은 많은 연산은 임의의 시퀀스형에 대해 작동한다.[67]다른 LISP 계열 언어와 마찬가지로, 커먼 리스프의 '''리스트'''는 cons[73] ('''cons 셀'''[74], '''쌍'''[75]이라고도 함)으로 구성된다. cons 셀은 car와 cdr 두 개의 슬롯을 갖춘 데이터 구조이다. 리스트는 cons 셀을 연결한 것이다. 각 cons 셀의 `car` 슬롯은 리스트의 요소(다른 리스트일 수도 있음)를 참조하고, `cdr` 슬롯은 다음 cons 셀을 참조한다. 단, 마지막 cons 셀의 `cdr`만 `nil`을 참조한다. cons 셀을 통해 쉽게 트리 구조나 다른 복잡한 데이터 구조를 구현할 수 있지만, 대부분 다른 자료 구조를 사용하거나 클래스 인스턴스를 사용하는 것이 권장된다.
'''커먼 리스프'''는 다차원 '''배열'''을 지원하며, 필요에 따라 배열의 크기를 동적으로 조절할 수 있다. 다차원 배열은 행렬 연산에 사용된다. '''벡터'''는 1차원 배열이다. 배열은 임의의 형식을 요소로 가질 수 있으며 (하나의 배열에 여러 형식의 요소를 혼합할 수도 있다), 정수 벡터와 같이 요소를 특정 형식으로 지정할 수도 있다. 많은 구현에서 형식이 지정된 배열을 사용할 경우 배열 연산 최적화가 가능하다. 형식이 지정된 배열 중 두 가지 유형이 표준으로 정의되어 있다. '''문자열'''은 문자를 요소로 하는 벡터이며, '''비트 벡터'''는 비트를 요소로 하는 벡터이다.[67]
비트 벡터와 벡터는 시퀀스의 하위 타입(subtype)이기도 하다.
'''해시 테이블'''은 데이터 객체 간의 관련성을 유지한다. 임의의 객체를 키 또는 값으로 사용할 수 있다. 해시 테이블은 배열처럼 필요에 따라 동적으로 크기가 조정된다. '''패키지'''는 심볼의 집합으로, 주로 프로그램의 일부를 네임스페이스로 분할하기 위해 사용된다. 패키지는 여러 심볼을 '''내보내기'''[76]함으로써 인터페이스를 공개한다. '''구조체'''는 C 언어의 구조체나 파스칼프랑스어의 레코드와 유사한, 여러 유형과 값의 필드(슬롯이라고 함)로 구성된 복합적인 데이터 구조이다. 클래스의 '''인스턴스'''[77]는 구조체와 유사하지만, 이는 객체 시스템에 의해 만들어진다.[67]
5. 함수
커먼 리스프는 일급 함수를 지원한다. 함수는 `defun` 매크로를 사용하여 정의하며, 함수의 이름, 인수의 이름, 함수 본체를 인수로 받는다. 함수 정의는 컴파일러에게 최적화 설정이나 인수의 데이터 유형에 대한 힌트를 제공하는 ''선언''을 포함할 수 있으며, Lisp 시스템이 대화형 문서를 제공하는 데 사용할 수 있는 ''문서화 문자열''(docstring)을 포함할 수도 있다.[78][79]
```lisp
(defun square (x)
"단정밀도 부동 소수점 x의 제곱을 계산합니다."
(declare (single-float x) (optimize (speed 3) (debug 0) (safety 1)))
(the single-float (* x x)))
```
익명 함수(함수 리터럴)는 `lambda` 표현식을 사용하여 정의한다. 예를 들어, 인수를 제곱하는 함수는 `(lambda (x) (* x x))`이다. Lisp 프로그래밍 스타일은 익명 함수를 인수로 사용하는 고차 함수를 자주 활용한다.
지역 함수는 `flet` 및 `labels`를 사용하여 정의할 수 있다.
```lisp
(flet ((square (x)
(* x x)))
(square 3))
```
`compile` 연산자를 사용하여 함수를 컴파일할 수 있다. (일부 Lisp 시스템은 별도로 컴파일 지시를 하지 않으면 기본적으로 인터프리터를 사용하여 함수를 실행한다.)
제네릭 함수는 `defgeneric` 매크로로 정의하며, 여러 메서드의 모음이다. `defmethod` 매크로는 메서드를 정의한다. 메서드는 CLOS ''표준 클래스'', ''시스템 클래스'', ''구조체 클래스'' 또는 개별 객체를 기반으로 매개변수를 특수화할 수 있다. 제네릭 함수가 호출되면, 다중 디스패치가 사용할 유효한 메서드를 결정한다.
```lisp
(defgeneric add (a b))
(defmethod add ((a number) (b number))
(+ a b))
(defmethod add ((a vector) (b number))
(map 'vector (lambda (n) (+ n b)) a))
(defmethod add ((a vector) (b vector))
(map 'vector #'+ a b))
(defmethod add ((a string) (b string))
(concatenate 'string a b))
(add 2 3) ; 5를 반환
(add #(1 2 3 4) 7) ; #(8 9 10 11)을 반환
(add #(1 2 3 4) #(4 3 2 1)) ; #(5 5 5 5)를 반환
(add "COMMON " "LISP") ; "COMMON LISP"를 반환
```
제네릭 함수는 일급 데이터 타입이기도 하다.
함수 이름 공간은 데이터 변수 이름 공간과 분리되어 있다. 이는 커먼 리스프와 Scheme의 주요 차이점이다. 커먼 리스프에서 함수 이름 공간에 이름을 정의하는 연산자에는 `defun`, `flet`, `labels`, `defmethod`, `defgeneric` 등이 있다. 함수를 다른 함수의 인수로 이름으로 전달하려면 `function` 특수 연산자(주로 `#'`로 축약)를 사용해야 한다.
Scheme은 평가 모델이 더 단순하여 하나의 네임스페이스만 가지며, 폼의 모든 위치가 (어떤 순서로든) 평가된다.
함수 네임스페이스 분리 여부는 리스프 커뮤니티에서 ''Lisp-1 대 Lisp-2 논쟁''으로 불리는 논쟁의 대상이다. Lisp-1은 Scheme 모델, Lisp-2는 커먼 리스프 모델을 가리킨다. 이 용어는 1988년 리처드 P. 가브리엘(Richard P. Gabriel)과 켄트 핏먼(Kent Pitman)의 논문에서 처음 사용되었다.[13][80]
5. 1. 다중 반환 값
커먼 리스프는 ''다중 값'' 개념을 지원한다.[14] 모든 표현식은 단일 ''주 값''을 가지지만, 여러 개의 ''부차 값''도 가질 수 있다. 이 부차 값은 호출자에 의해 수신 및 검사될 수 있다. 부차 값은 선택 사항이며 전용 사이드 채널을 통해 전달되므로, 호출자는 부차 값을 필요로 하지 않는 경우 그 존재를 전혀 인식하지 못할 수도 있다. 이는 때때로 유용한 정보를 전달하는 데 편리한 메커니즘이다.예를 들어:
- `TRUNCATE` 함수[15]는 주어진 숫자를 0을 향해 정수로 반올림하고, 나머지 값도 부차 값으로 반환한다. 이를 통해 잘린 값을 쉽게 확인할 수 있다. 또한 선택적 제수 매개변수를 지원하여 유클리드 나눗셈을 간단하게 수행할 수 있다.
```cl
(let ((x 1266778)
(y 458))
(multiple-value-bind (quotient remainder)
(truncate x y)
(format nil "~A divided by ~A is ~A remainder ~A" x y quotient remainder)))
;;;; => "1266778 divided by 458 is 2765 remainder 408"
```
- `GETHASH`[16]는 연관 맵에서 키의 값을 반환하거나, 값이 없으면 기본값을 반환한다. 또한 값이 발견되었는지 여부를 나타내는 부차 부울 값도 반환한다. 값이 발견되었는지 또는 기본값으로 제공되었는지에 대해 신경 쓰지 않는 코드는 그대로 사용할 수 있지만, 구분이 중요한 경우 부차 부울 값을 검사하고 적절하게 반응할 수 있다.
```cl
(defun get-answer (library)
(gethash 'answer library 42))
(defun the-answer-1 (library)
(format nil "The answer is ~A" (get-answer library)))
;;;; Returns "The answer is 42" if ANSWER not present in LIBRARY
(defun the-answer-2 (library)
(multiple-value-bind (answer sure-p)
(get-answer library)
(if (not sure-p)
"I don't know"
(format nil "The answer is ~A" answer))))
;;;; Returns "I don't know" if ANSWER not present in LIBRARY
```
다중 값은 몇 가지 표준 형식에서 지원된다. 부차 값에 접근하기 위한 특수 형식인 `multiple-value-bind`와 다중 값을 반환하기 위한 `values`가 가장 일반적이다.
```cl
(defun magic-eight-ball ()
"Return an outlook prediction, with the probability as a secondary value"
(values "Outlook good" (random 1.0)))
;;;; => "Outlook good"
;;;; => 0.3187
6. 스코프
다른 많은 프로그래밍 언어와 마찬가지로, 커먼 리스프영어 프로그램은 변수, 함수 등 여러 종류의 개체를 참조하기 위해 이름을 사용한다. 이름과 그 이름이 참조하는 개체 간의 연관을 바인딩[84]이라고 한다. 명명된 참조는 유효 범위에 따라 달라진다.
유효 범위는 이름이 특정 바인딩을 갖는 것으로 결정되는 상황 집합을 의미한다. 커먼 리스프에서 스코프를 결정하는 상황은 다음과 같다.
- 표현식 내에서 참조의 위치.
- 참조가 이루어지는 표현식의 종류.
- 프로그램 텍스트 내에서 참조의 위치.
- 변수 참조의 경우, 변수 기호가 로컬 또는 전역적으로 특수하게 선언되었는지 여부.
- 참조가 해결되는 환경의 특정 인스턴스.
커먼 리스프 프로그래머는 기호가 무엇을 참조하는지 이해하기 위해, 어떤 종류의 참조가 표현되고 있는지, 변수 참조인 경우 어떤 종류의 스코프(동적 대 렉시컬 스코프)를 사용하는지, 런타임 상황도 알아야 한다.
리스프의 일부 환경은 전역적으로 널리 퍼져 있다. 예를 들어, 새로운 자료형이 정의되면 그 이후 어디에서나 알려진다. 해당 자료형에 대한 참조는 이 전역 환경에서 해당 정보를 찾는다.
커먼 리스프는 렉시컬 스코프와 동적 스코프를 모두 지원한다.
6. 1. 렉시컬 스코프
커먼 리스프는 어휘 환경을 지원한다. 어휘 환경의 바인딩은 어휘 범위를 가지며, 네임스페이스의 유형에 따라 무기한 범위 또는 동적 범위를 가질 수 있다. 어휘 범위는 가시성이 바인딩이 설정된 블록으로 물리적으로 제한된다는 것을 의미한다. 해당 블록에 텍스트적으로 (즉, 어휘적으로) 포함되지 않은 참조는 해당 바인딩을 단순히 볼 수 없다.[17]`TAGBODY`의 태그는 어휘 범위를 갖는다. 표현식 `(GO X)`는 레이블 `X`를 포함하는 `TAGBODY`에 포함되어 있지 않으면 오류이다. 그러나 레이블 바인딩은 `TAGBODY`가 실행을 종료할 때 사라지는데, 이는 동적 범위를 갖기 때문이다. 코드 블록이 어휘 클로저 호출에 의해 다시 입력되면, 해당 클로저의 본문이 `GO`를 통해 태그로 제어를 전송하려고 시도하는 것은 유효하지 않다.[17]
Lisp의 로컬 함수 바인딩은 어휘 범위를 가지며, 변수 바인딩도 기본적으로 어휘 범위를 갖는다. `GO` 레이블과 대조적으로 이 둘은 모두 무기한 범위를 갖는다. 어휘 함수 또는 변수 바인딩이 설정되면 해당 바인딩은 해당 바인딩을 설정한 구문이 종료된 후에도 이에 대한 참조가 가능한 한 지속된다. 어휘 변수 및 함수에 대한 참조는 어휘 클로저 덕분에 설정 구문이 종료된 후에도 가능하다.[17]
어휘 바인딩은 커먼 리스프 변수의 기본 바인딩 모드이다. 개별 기호의 경우 로컬 선언 또는 전역 선언을 통해 동적 범위로 전환할 수 있다. 후자는 `DEFVAR` 또는 `DEFPARAMETER`와 같은 구문을 사용하여 암묵적으로 발생할 수 있다. 특수(즉, 동적으로 범위가 지정된) 변수가 "earmuff 규칙"이라고 하는 것에서 별표 시길 `*`로 시작하고 끝나는 이름을 갖는 것은 커먼 리스프 프로그래밍에서 중요한 규칙이다.[17] 이 규칙을 따르면 특수 변수에 대한 별도의 네임스페이스가 효과적으로 생성되어 어휘 변수가 의도적으로 특수 변수가 되는 것을 방지할 수 있다.[17]
어휘 범위는 여러 가지 이유로 유용하다.[17]
- 첫째, 변수 및 함수에 대한 참조는 런타임 환경 구조가 상대적으로 단순하기 때문에 효율적인 기계 코드로 컴파일될 수 있다. 많은 경우 스택 저장소로 최적화될 수 있으므로 어휘 범위를 열고 닫는 데 최소한의 오버헤드가 발생한다. 전체 클로저를 생성해야 하는 경우에도 클로저의 환경에 대한 접근은 여전히 효율적이다. 일반적으로 각 변수는 바인딩 벡터의 오프셋이 되므로 변수 참조는 기본 플러스 오프셋 주소 지정 모드가 있는 간단한 로드 또는 저장 명령이 된다.
- 둘째, 어휘 범위(무기한 범위와 결합)는 일급 객체인 함수 사용을 중심으로 하는 프로그래밍의 전체 패러다임을 생성하는 어휘 클로저를 낳으며, 이는 함수형 프로그래밍의 근본이다.
- 셋째, 아마도 가장 중요한 것은 어휘 클로저를 활용하지 않더라도 어휘 범위의 사용은 프로그램 모듈을 원치 않는 상호 작용으로부터 격리한다는 것이다. 어휘 변수는 가시성이 제한되어 있어 비공개이다. 한 모듈 A가 어휘 변수 X를 바인딩하고 다른 모듈 B를 호출하는 경우, B의 X에 대한 참조는 A에 바인딩된 X로 우연히 해석되지 않는다. B는 X에 접근할 수 없다. 변수를 통한 규율 있는 상호 작용이 원하는 상황을 위해 커먼 리스프는 특수 변수를 제공한다. 특수 변수를 사용하면 모듈 A가 A에서 호출되는 다른 모듈 B에 표시되는 변수 X에 대한 바인딩을 설정할 수 있다. 이렇게 할 수 있는 것은 장점이며, 이것이 발생하는 것을 방지할 수 있는 것도 장점이다. 결과적으로 커먼 리스프는 어휘 범위와 동적 범위를 모두 지원한다.
6. 2. 동적 스코프
커먼 리스프에서 동적 환경은 환경의 한 유형이다. 이 환경에서 설정된 바인딩은 동적 범위를 가지는데, 이는 `let` 블록과 같은 특정 구문의 실행 시작 시점에 바인딩이 설정되고 해당 구문의 실행이 종료될 때 사라진다는 것을 의미한다. 즉, 바인딩의 수명은 블록의 동적 활성화 및 비활성화와 연관된다. 그러나 동적 바인딩은 해당 블록 내에서만 보이는 것이 아니라 해당 블록에서 호출된 모든 함수에도 보인다. 이러한 유형의 가시성을 무제한 범위라고 한다. 동적 범위(수명이 블록의 활성화 및 비활성화와 연관됨)와 무제한 범위(해당 블록에서 호출된 모든 함수에 표시됨)를 나타내는 바인딩을 동적 범위라고 한다.커먼 리스프는 특수 변수라고도 하는 동적 범위 변수를 지원한다. 재시작 및 캐치 태그와 같은 특정 종류의 다른 바인딩은 반드시 동적으로 범위가 지정된다. 함수 바인딩은 `flet`을 사용하여 동적으로 범위를 지정할 수 없지만(렉시컬 범위 함수 바인딩만 제공), 함수 객체(커먼 리스프의 첫 번째 수준 객체)는 동적 범위에서 `let`을 사용하여 바인딩된 동적 범위 변수에 할당된 다음 `funcall` 또는 `APPLY`를 사용하여 호출할 수 있다.
7. 매크로
리스프의 매크로는 함수와 비슷하게 사용되지만, 평가될 표현식을 나타내는 대신 프로그램 소스 코드의 변환을 나타낸다. 매크로는 `defmacro` 매크로로 정의된다. 지역 매크로는 `macrolet` 특수 연산자를 사용하여 정의할 수 있다. 심볼 매크로는 `define-symbol-macro` 및 `symbol-macrolet`을 사용하여 정의할 수 있다.[1]
매크로는 프로그래머가 언어 내에 새로운 구문 형식을 만들 수 있도록 해준다. 일반적인 사용 예시는 다음과 같다:[1]
- 새로운 제어 구조 (예: 반복 구조, 분기 구조)
- 스코핑 및 바인딩 구조
- 복잡하고 반복적인 소스 코드에 대한 단순화된 구문
- 컴파일 타임 부작용이 있는 최상위 정의 형식
- 데이터 중심 프로그래밍
- 내장된 도메인 특화 언어 (예: SQL, HTML, 프롤로그)
- 암묵적인 최종화 형식
`setf` 추상화, `with-accessors`, `with-slots`, `with-open-file`과 같은 다양한 표준 커먼 리스프 기능도 매크로로 구현되어 있다.[1]
폴 그레이엄의 저서 On Lisp와 더그 호이트의 저서 Let Over Lambda는 커먼 리스프에서 매크로 사용법을 자세히 설명한다.[1] 호이트는 그의 저서에서 "매크로는 리스프가 프로그래밍 언어로서 갖는 가장 큰 장점이며, 모든 프로그래밍 언어의 가장 큰 장점이다"라고 주장한다.[1]
매크로는 S-표현식을 입력받아 추상 구문 트리와 유사한 형태로 변환하여 반환하는 함수로 생각할 수 있다. 이러한 함수는 평가기나 컴파일러보다 먼저 호출되어 최종 소스 코드를 생성한다. 매크로는 일반적인 커먼 리스프로 작성되며, 사용 가능한 모든 커먼 리스프 연산자를 사용할 수 있다.[1]
7. 1. 매크로를 사용한 새로운 제어 구조 정의 예시
매크로는 리스프 프로그래머가 언어에서 새로운 구문 형식을 만들 수 있도록 한다. 일반적인 사용 사례 중 하나는 새로운 제어 구조를 만드는 것이다. 다음은 `until` 반복 구문을 제공하는 매크로 예시이다.구문:
```text
(until test form*)
```
`until` 매크로 정의:
```lisp
(defmacro until (test &body body)
(let ((start-tag (gensym "START"))
(end-tag (gensym "END")))
`(tagbody ,start-tag
(when ,test (go ,end-tag))
(progn ,@body)
(go ,start-tag)
,end-tag)))
```
`tagbody`는 태그 이름을 지정하고 `go` 형식을 사용하여 해당 태그로 점프하는 기능을 제공하는 기본 커먼 리스프 특수 연산자이다. 백틱(`)은 쉼표로 앞에 오는 폼의 값이 채워지는 코드 템플릿을 제공한다. 쉼표와 앳 사인(@)으로 앞에 오는 폼은 'spliced'된다. tagbody 형식은 종료 조건을 테스트한다. 조건이 참이면 종료 태그로 점프한다. 그렇지 않으면 제공된 본문 코드가 실행된 다음 시작 태그로 점프한다.
`until` 매크로 사용 예시:
```lisp
(until (= (random 10) 0)
(write-line "Hello"))
```
이 코드는 `macroexpand-1` 함수를 사용하여 확장할 수 있다. 위 예제의 확장은 다음과 같다.
```lisp
(TAGBODY
#:START1136
(WHEN (ZEROP (RANDOM 10))
(GO #:END1137))
(PROGN (WRITE-LINE "hello"))
(GO #:START1136)
#:END1137)
```
매크로 확장 중에 변수 `test`의 값은 `(= (random 10) 0)`이고, 변수 `body`의 값은 `((write-line "Hello"))`이다. 본문은 형식의 목록이다.
기호는 일반적으로 자동으로 대문자로 변환된다. 확장은 두 개의 레이블이 있는 TAGBODY를 사용한다. 이러한 레이블에 대한 기호는 GENSYM에 의해 계산되며 어떤 패키지에도 인터닝되지 않는다. 두 개의 `go` 형식은 이러한 태그를 사용하여 점프한다. `tagbody`는 커먼 리스프의 기본 연산자(매크로가 아님)이므로 다른 것으로 확장되지 않는다. 확장된 형식은 `when` 매크로를 사용하며 이 또한 확장된다. 소스 형식을 완전히 확장하는 것을 '코드 워킹'이라고 한다.
완전히 확장된('walked') 형식에서 `when` 형식은 기본 `if`로 대체된다.
```lisp
(TAGBODY
#:START1136
(IF (ZEROP (RANDOM 10))
(PROGN (GO #:END1137))
NIL)
(PROGN (WRITE-LINE "hello"))
(GO #:START1136))
#:END1137)
```
다른 정의:
```lisp
(defmacro until (test &body body)
`(do ()
(,test)
,@body))
```
```lisp
;; 사용 예
(until (= (random 10) 0)
(write-line "Hello"))
;; 정의한 until 매크로 전개
(macroexpand-1 '(until (= (random 10) 0)
(write-line "Hello")))
→ (DO ()
((= (RANDOM 10) 0))
(WRITE-LINE "Hello"))
T
```
모든 매크로는 해당 매크로를 포함하는 소스 코드를 일반적으로 평가하거나 컴파일하기 전에 확장해야 한다. 매크로는 S-표현식을 수락하고 반환하는 함수로 간주할 수 있다. 이는 추상 구문 트리와 유사하지만 이에 국한되지는 않는다. 이러한 함수는 최종 소스 코드를 생성하기 위해 평가자 또는 컴파일러 전에 호출된다. 매크로는 일반 커먼 리스프로 작성되며 사용 가능한 모든 커먼 리스프(또는 타사) 연산자를 사용할 수 있다.
8. 조건 시스템
커먼 리스프에서 예외 처리는 ''조건 시스템''이 담당한다.[18] 조건 시스템은 ''조건'', ''핸들러'', ''재시작''을 제공한다. ''조건''은 오류와 같은 예외적인 상황을 설명하는 객체이다. ''조건''이 시그널되면 커먼 리스프 시스템은 이 조건 유형에 대한 ''핸들러''를 검색하여 핸들러를 호출한다. ''핸들러''는 재시작을 검색하고, 조건 유형 및 조건 객체의 일부로 제공된 관련 정보와 같은 정보를 사용하여 현재 문제를 자동으로 수정하기 위해 이러한 재시작 중 하나를 사용하고 적절한 재시작 함수를 호출할 수 있다.
이러한 재시작은 코드에 의해 처리되지 않으면 사용자에게 (예를 들어 디버거의 사용자 인터페이스의 일부로) 제공될 수 있으므로 사용자가 사용 가능한 재시작 중 하나를 선택하고 호출할 수 있다. 조건 핸들러는 오류의 컨텍스트에서 (스택을 언와인드하지 않고) 호출되므로, 다른 예외 처리 시스템이 이미 현재 루틴을 종료했을 많은 경우에서 완벽한 오류 복구가 가능하다. 디버거 자체도 `*debugger-hook*` 동적 변수를 사용하여 사용자 정의하거나 대체할 수 있다. 파이널라이저와 같은 ''unwind-protect'' 형식 내에서 발견된 코드는 예외에도 불구하고 적절하게 실행된다.
다음 예시( Symbolics Genera 사용)에서 사용자는 Read-Eval-Print-LOOP (REPL)에서 호출된 Lisp 함수 ''test''에서 파일이 존재하지 않을 때 파일을 열려고 한다. 리스프 시스템은 네 가지 재시작을 제공한다. 사용자는 ''Retry OPEN using a different pathname'' 재시작을 선택하고 다른 경로(lispm-int.lisp 대신 lispm-init.lisp)를 입력한다. 사용자 코드는 오류 처리 코드를 포함하지 않는다. 전체 오류 처리 및 재시작 코드는 리스프 시스템에서 제공하며, 이는 사용자 코드를 종료하지 않고도 오류를 처리하고 수정할 수 있다.
Command: (test ">zippy>lispm-int.lisp")
Error: The file was not found.
For lispm:>zippy>lispm-int.lisp.newest
LMFS:OPEN-LOCAL-LMFS-1
Arg 0: #P"lispm:>zippy>lispm-int.lisp.newest"
s-A,
s-B: Retry OPEN using a different pathname
s-C,
s-D: Restart process TELNET terminal
Use what pathname instead [default lispm:>zippy>lispm-int.lisp.newest]:
lispm:>zippy>lispm-init.lisp.newest
...the program continues
9. 커먼 리스프 객체 시스템 (CLOS)
커먼 리스프 객체 시스템(CLOS)은 객체 지향 프로그래밍을 위한 도구이다. 피터 노르비그는 CLOS의 특징(다중 상속, 믹스인, 다중 메소드, 메타클래스, 메소드 조합 등)을 갖춘 동적 언어에서 많은 디자인 패턴을 구현하는 것이 얼마나 더 간단한지를 설명한다.[19]
CLOS는 동적 프로그래밍 언어 객체 시스템으로, 다중 디스패치와 다중 상속을 지원하며, C++(C++)나 자바(Java)와 같은 정적 언어에서 발견되는 OOP 기능과는 근본적으로 다르다. 동적 객체 시스템으로서 CLOS는 런타임에 제네릭 함수와 클래스에 대한 변경을 허용한다. 메소드를 추가 및 제거하고, 클래스를 추가 및 재정의할 수 있으며, 객체를 클래스 변경에 맞게 업데이트하고, 객체의 클래스를 변경할 수 있다.
CLOS는 ANSI 커먼 리스프에 통합되었다. 제네릭 함수는 일반 함수처럼 사용할 수 있으며, 일급 데이터 타입이다. 모든 CLOS 클래스는 커먼 리스프 타입 시스템에 통합된다. 많은 커먼 리스프 타입은 해당 클래스를 가지고 있다. 커먼 리스프에서 CLOS의 잠재적인 사용 사례가 더 많다. 이 규격은 조건(conditions)이 CLOS로 구현되는지 여부를 명시하지 않는다. 경로명과 스트림은 CLOS로 구현될 수 있다. ANSI 커먼 리스프에서 CLOS의 이러한 추가적인 사용 가능성은 표준의 일부가 아니다. 실제 커먼 리스프 구현에서는 경로명, 스트림, 입출력, 조건, CLOS 자체의 구현 등에 CLOS를 사용한다.
10. 컴파일러와 인터프리터
커먼 리스프는 인터프리터와 컴파일러를 모두 제공한다.[17] 컴파일러는 개별 Lisp 함수를 메모리에서 컴파일하거나 전체 파일을 외부 저장된 컴파일된 코드 (''fasl'' 파일)로 컴파일할 수 있다.[17]
이전 Lisp 방언들은 인터프리터와 컴파일러에서 서로 다른 의미를 가지는 경우가 있었지만, 커먼 리스프는 기본적으로 정적 스코핑을 사용하도록 요구한다.[17] 커먼 리스프 표준은 인터프리터와 컴파일러의 의미를 모두 설명하며, 컴파일러는 개별 함수에 대해 `compile` 함수를, 파일에 대해 `compile-file` 함수를 사용하여 호출할 수 있다.[17]
커먼 리스프는 유형 선언을 허용하고 컴파일러 코드 생성 정책에 영향을 미치는 방법을 제공한다. 다양한 최적화 품질에 대해 0 (중요하지 않음)에서 3 (가장 중요함) 사이의 값을 지정할 수 있으며, `speed` (속도), `space` (공간), `safety` (안전성), `debug` (디버그) 및 `compilation-speed` (컴파일 속도)가 있다.[17]
Lisp 코드를 평가하는 `eval` 함수도 있다. `eval`은 텍스트 문자열이 아닌 미리 구문 분석된 S-표현식으로 코드를 사용하며, Clozure CL 및 SBCL과 같은 여러 커먼 리스프 구현은 컴파일러를 사용하여 `eval`을 구현한다.[17]
파일 컴파일러는 `compile-file` 함수를 사용하여 호출되며, 컴파일된 코드로 생성된 파일은 ''fasl'' (from ''fast load'') 파일이라고 한다. 이러한 ''fasl'' 파일과 소스 코드 파일은 `load` 함수를 사용하여 실행 중인 커먼 리스프 시스템에 로드할 수 있다. 구현에 따라 파일 컴파일러는 바이트 코드 (예: 자바 가상 머신), C 언어 코드 (C 컴파일러로 컴파일됨) 또는 직접 네이티브 코드를 생성한다.[17]
커먼 리스프 구현은 코드가 완전히 컴파일되더라도 대화식으로 사용할 수 있다. 따라서 인터프리터 언어의 개념은 대화식 커먼 리스프에는 적용되지 않는다.[17]
11. 다른 Lisp 방언과의 비교
커먼 리스프는 Scheme과 가장 자주 비교된다. 이 두 언어는 가장 유명한 LISP 계열 언어이기 때문이다. Scheme은 커먼 리스프보다 먼저 나왔으며, 같은 LISP 전통에서 생겨났을 뿐만 아니라, 커먼 리스프 표준 위원회 의장을 맡았던 가이 스틸 주니어(Guy L. Steele Jr.)[85]와 같은 엔지니어에게서 비롯되었다.
이전의 많은 Lisp 방언 및 구현과는 달리, 커먼 리스프는 Scheme과 마찬가지로 기본적으로 정적 스코프만을 사용한다. MACLISP와 같이 커먼 리스프의 설계에 기여한 많은 구현은 인터프리터에서는 동적 스코프를, 컴파일러에서는 정적 스코프를 사용하는 동작을 보였다. Scheme은 그러한 것과는 달리 정적 스코프만을 사용했다. 커먼 리스프는 동적 스코프도 지원하지만, 명시적인 `special` 선언이 필요하다. ANSI 커먼 리스프의 인터프리터와 컴파일러 사이에는 스코프에 관해서 전혀 차이점이 존재하지 않는다.
때때로 커먼 리스프는 "Lisp-2", Scheme은 "Lisp-1"이라고 불리기도 한다. 이는 커먼 리스프가 함수명과 변수명('두 개')에 각각 독립적인 이름을 가지고 있기 때문에 붙여진 이름이다. 그러나 실제로는 커먼 리스프가 `go` 태그나 블록명, `loop` 키워드 등 많은 네임스페이스를 가지고 있으며, 매크로를 잘 사용하면 구문적으로 네임스페이스를 추가할 수도 있다. 여러 네임스페이스에 관한 장단점에 대해 커먼 리스프와 Scheme을 각각 지지하는 논쟁이 오랫동안 진행되어 왔다. Scheme에서는 변수명과 함수명의 충돌을 피해야 하므로, Scheme의 함수는 종종 `lis`나 `lst`, `lyst`와 같은 함수명과 충돌하지 않는 인자명을 사용하게 된다. 반면 커먼 리스프에서는 인자로 사용할 경우 명시적으로 함수의 네임스페이스를 참조해야 한다. 이는 위에 언급된 `sort`의 예시처럼 일반적인 경우이다.
커먼 리스프는 또한 참/거짓 값의 처리 방식이 Scheme과 다르다. Scheme은 참과 거짓을 표현하기 위해 `#t`와 `#f`라는 특별한 값을 사용한다. 커먼 리스프는 더 오래된 LISP 계열 언어의 전통에 따라 심볼 `t`와 `nil`[86]을 사용한다. 커먼 리스프에서는 `if`와 같은 조건식에서 임의의 `nil`이 아닌 값이 참으로 처리된다. 이로 인해 몇몇 연산자는 술어 역할을 하면서 동시에, 후속 계산에 사용할 수 있는 유의미한 값을 반환할 수 있게 된다.
Scheme의 표준 규격은 꼬리 재귀 최적화를 요구하지만, 커먼 리스프의 규격은 그렇지 않다. 대부분의 커먼 리스프 구현은 꼬리 재귀 최적화를 제공하지만, 프로그래머가 최적화 선언을 사용한 경우에만 적용되는 경우가 많다. 그럼에도 불구하고, 일반적인 커먼 리스프의 코딩 스타일은 Scheme 스타일에서 선호되는 모든 경우에 재귀를 사용하는 방식과는 다르다. Scheme 프로그래머가 꼬리 재귀로 표현하는 것을, 커먼 리스프 프로그래머는 `do`, `dolist`, `loop` 등의 반복 구문을 사용해서 표현한다.
12. 구현체
커먼 리스프는 Perl과 같은 단일 구현체가 아닌, 에이다나 C와 같이 사양에 의해 정의되는 프로그래밍 언어이다. 여러 구현체들이 존재하며, 표준은 구현체들이 유효하게 다를 수 있는 영역을 명시하고 있다.
각 구현체들은 표준에서 다루지 않는 기능을 제공하는 확장들을 포함하는 경향이 있다. 이러한 확장에는 다음이 포함될 수 있다.
- 대화형 최상위 레벨 (REPL)
- 가비지 컬렉션
- 디버거, 스텝퍼 및 검사기
- 약한 데이터 구조 (해시 테이블)
- 확장 가능한 시퀀스
- 확장 가능한 LOOP
- 환경 접근
- CLOS 메타 객체 프로토콜
- CLOS 기반 확장 가능한 스트림
- CLOS 기반 조건 시스템
- 네트워크 스트림
- 영구적인 CLOS
- 유니코드 지원
- 외국어 인터페이스 (주로 C)
- 운영 체제 인터페이스
- Java 인터페이스
- 스레드 및 멀티 프로세싱
- 애플리케이션 제공 (애플리케이션, 동적 라이브러리)
- 이미지 저장
이러한 확장들을 이식 가능하게 지원하기 위해 자유-오픈 소스 소프트웨어 라이브러리들이 Common-Lisp.net[20] 및 CLOCC (Common Lisp Open Code Collection)[21] 프로젝트 저장소 등에서 제공되고 있다.
커먼 리스프 구현체는 네이티브 코드 컴파일, 바이트 코드 컴파일, 인터프리테이션을 혼합하여 사용할 수 있도록 설계되었다. 언어 사양에는 컴파일 최적화를 위한 표준 선언(예: 함수 인라인 또는 타입 특수화)이 제안되어 있다. 대부분의 커먼 리스프 구현체는 소스 코드를 네이티브 머신 코드로 컴파일하며, 일부는 최적화된 독립 실행형 애플리케이션을 생성할 수 있다. 인터프리트된 바이트 코드로 컴파일하는 구현체는 네이티브 코드보다 효율성은 떨어지지만 바이너리 코드 이식성이 용이하다. 일부 컴파일러는 커먼 리스프 코드를 C 코드로 컴파일하기도 한다. 커먼 리스프가 순수하게 인터프리트되는 언어라는 오해는 Lisp 환경의 대화형 프롬프트와 증분 컴파일 방식 때문일 수 있다.
CLISP, SBCL 등 일부 유닉스 기반 구현체는 스크립팅 언어로 사용될 수 있는데, 이는 Perl이나 유닉스 셸 인터프리터처럼 시스템에서 투명하게 호출되는 방식이다.[22]
12. 1. 상용 구현체
다음은 커먼 리스프의 상용 구현체들이다.- '''알레그로 공통 리스프(Allegro Common Lisp)''': 프란츠(Franz)[99]에서 만든 처리계이다. 마이크로소프트 윈도우, 프리BSD, 리눅스, 애플 macOS 및 다양한 UNIX 변종을 지원한다. 알레그로 CL은 통합 개발 환경(IDE) (윈도우 및 리눅스용)을 제공하며, 애플리케이션 배포를 위한 광범위한 기능을 갖추고 있다.
- '''리퀴드 공통 리스프(Liquid Common Lisp)''': 이전 이름은 루시드 공통 리스프(Lucid Common Lisp)이다. 유지보수만 진행되며, 새로운 릴리스는 없다.
- '''리스프웍스(LispWorks)''': 리스프웍스(LispWorks)[100]에서 만든 처리계이다. 마이크로소프트 윈도우, 프리BSD, 리눅스, 애플 macOS, iOS, 안드로이드 및 다양한 UNIX 변종을 지원한다. 리스프웍스는 통합 개발 환경(IDE) (대부분의 플랫폼에서 사용 가능하지만, iOS 및 안드로이드에서는 지원하지 않음)과 애플리케이션 배포를 위한 광범위한 기능을 제공한다.
- '''mocl''': iOS, 안드로이드 및 macOS를 지원한다.
- '''오픈 제네라(Open Genera)''': DEC Alpha를 지원한다.
- '''사이니어 공통 리스프(Scieneer Common Lisp)''': 사이니어(Scieneer)[101]에서 만든 처리계로 고성능 과학 컴퓨팅을 위해 설계되었다.
12. 2. 자유 배포 가능 구현체
- Armed Bear Common Lisp(ABCL): 자바 가상 머신에서 실행되는 구현체이다.[23] 자바 바이트 코드 컴파일러를 포함하며, 커먼 리스프 프로그램에서 자바 라이브러리에 접근할 수 있다. 이전에는 Armed Bear J Editor의 구성 요소였다.[93]
- Clasp: C++ 라이브러리와 원활하게 상호 운용되는 LLVM 기반 구현체이다. 여러 유닉스 및 유닉스 계열 시스템(macOS 포함)에서 실행된다.
- CLISP: 바이트코드 컴파일 구현체로 이식성이 뛰어나며, macOS를 포함한 여러 유닉스 및 유닉스 계열 시스템뿐만 아니라, 마이크로소프트 윈도우 및 기타 여러 시스템에서 실행된다.[94]
- Clozure CL (CCL): 원래 Macintosh Common Lisp의 자유-오픈 소스 소프트웨어 포크였다. macOS, FreeBSD, Linux, Solaris 및 Windows에서 실행된다. 각 플랫폼에서 32비트 및 64비트 x86 포트가 지원된다. 또한 Mac OS 및 Linux용 Power PC 포트가 있다. CCL은 이전에 OpenMCL로 알려졌지만 Macintosh Common Lisp의 오픈 소스 버전과의 혼동을 피하기 위해 더 이상 해당 이름을 사용하지 않는다.[91][92]
- CMUCL: 원래 카네기 멜론 대학교에서 시작되었으며, 현재는 자원 봉사자 그룹에 의해 자유-오픈 소스 소프트웨어로 유지 관리된다. 빠른 네이티브 코드 컴파일러를 사용한다. Intel x86용 Linux 및 BSD에서 사용할 수 있으며, Alpha용 Linux, Intel x86 및 PowerPC용 macOS, Solaris, IRIX 및 HP-UX에서 해당 네이티브 플랫폼에서 사용할 수 있다.[90]
- Corman Common Lisp: 마이크로소프트 윈도우용. 2015년 1월 MIT 라이선스 하에 게시되었다.[24][97][98]
- Embeddable Common Lisp (ECL): C 컴파일러를 통해 Lisp 코드를 머신 코드로 컴파일할 수 있다. C 프로그램에 ECL을 임베딩하고, C 코드를 Common Lisp 프로그램에 넣는 것도 가능하다.[93]
- GNU Common Lisp (GCL): GNU 프로젝트의 Lisp 컴파일러이다. 아직 ANSI를 완전히 준수하지는 않지만, Maxima, AXIOM 및 (역사적으로) ACL2를 포함한 여러 대규모 프로젝트에 사용되는 구현체이다. 11개의 다른 아키텍처에서 Linux에서 실행되며, Windows, Solaris 및 FreeBSD에서도 실행된다.[94]
- Macintosh Common Lisp (MCL): Mac OS X를 실행하는 PowerPC 프로세서가 있는 Apple Macintosh 컴퓨터용 버전 5.2는 오픈 소스이다. RMCL(MCL 5.2 기반)은 Apple의 Rosetta 바이너리 변환기를 사용하여 Intel 기반 Apple Macintosh 컴퓨터에서 실행된다.[95]
- ManKai Common Lisp (MKCL): ECL의 분기이다. 대폭 수정된 네이티브 다중 스레드 런타임 시스템을 통해 안정성, 안정성 및 전반적인 코드 품질을 강조한다. Linux에서 MKCL은 완벽하게 POSIX를 준수하는 런타임 시스템을 갖추고 있다.
- Movitz: 기본 OS에 의존하지 않고 x86 컴퓨터를 위한 Lisp 환경을 구현한다.
- Poplog: CL 버전을 POP-11과 선택적으로 Prolog, Standard ML (SML)과 함께 구현하여 혼합 언어 프로그래밍을 허용한다. 이 모든 경우 구현 언어는 POP-11이며 점진적으로 컴파일된다. 또한 컴파일러와 통신하는 통합된 Emacs와 유사한 편집기가 있다.
- Steel Bank Common Lisp (SBCL): CMUCL의 분기이다. "대략적으로 말해서 SBCL은 유지 관리성에 더 중점을 둔다는 점에서 CMU CL과 다르다."[25] HP/UX를 제외하고 CMUCL이 실행되는 플랫폼에서 실행된다. 또한 AMD64, PowerPC, SPARC, MIPS, Windows x86 및 AMD64용 Linux에서 실행된다.[26] 기본적으로 인터프리터를 사용하지 않으며, 사용자가 인터프리터를 켜지 않는 한 모든 표현식은 네이티브 코드로 컴파일된다. SBCL 컴파일러는 이전 버전의 The Computer Language Benchmarks Game에 따라 빠른 네이티브 코드를 생성한다.[27][89]
- Ufasoft Common Lisp: C++로 작성된 코어를 사용하여 윈도우 플랫폼용 CLISP를 포팅했다.
- Jatha영어: Common Lisp영어의 대부분을 서브셋으로 구현한 Java영어 라이브러리이다.[96]
13. 응용 프로그램
커먼 리스프는 연구용 애플리케이션(주로 인공지능) 개발, 프로토타입의 신속한 개발, 배포된 애플리케이션 등에 사용된다.
커먼 리스프는 야후! 스토어 웹 상거래 사이트를 포함한 많은 상업용 애플리케이션에 사용되었는데, 야후! 스토어는 원래 폴 그레이엄이 참여하여 개발하였으나 나중에 C++와 Perl로 다시 작성되었다.[47]
커먼 리스프로 작성된 오픈 소스 애플리케이션도 있는데, ACL2, Axiom, Maxima, OpenMusic, Pgloader,[64] Stumpwm 등이 있다.
13. 1. 상용 애플리케이션 예시
- 야후 스토어: 웹 상거래 사이트로, 폴 그레이엄이 개발에 참여했으나 나중에 C++와 Perl로 다시 작성되었다.[47]
- ITA 소프트웨어의 저가 항공권 검색 엔진: Orbitz, Kayak.com과 같은 여행 웹사이트와 아메리칸 항공, 컨티넨탈 항공, US 에어웨이와 같은 항공사에서 사용된다.
- 너티 독의 ''잭 앤 닥스터'' 비디오 게임 시리즈 개발 환경
- Grammarly의 핵심 문법 엔진: 커먼 리스프로 작성되었다.[56]
13. 2. 오픈 소스 애플리케이션 예시
- ACL2: 정리 증명용 시스템이다.
- Maxima: 대수적 수식 처리 전문가 시스템이다. GPL로 공개되어 자유롭게 입수할 수 있다. 미분 방정식이나 부정 적분처럼 해가 식인 것은, 사람이 푸는 것과 마찬가지로, 식의 형태로 해를 반환할 수 있다. 리처드 페이트먼 교수에 의해 작성된 Macsyma의 커먼 리스프 상의 재구현이다.[115]
- Compo영어: 복잡한 음악 구조를 자연스러운 방식으로 표현하는 것을 가능하게 한 언어이다.[115]
- Lisa: 지능형 에이전트 작성을 위한 규칙 기반 프로덕션 시스템이다.[116]
참조
[1]
웹사이트
ANSI Standards Action - December 28, 2018
https://share.ansi.o[...]
[2]
웹아카이브
Quoted from cover of cited standard. ANSI INCITS 226-1994 [S2008], for sale on standard's document page
https://webstore.ans[...]
2020-09-27
[3]
웹사이트
CLHS: About the Common Lisp HyperSpec (TM)
http://www.lispworks[...]
[4]
웹사이트
CLHS: Section 1.1.2
http://www.lispworks[...]
[5]
웹사이트
Common Lisp Implementations: A Survey
https://web.archive.[...]
2007-12-22
[6]
웹사이트
Old LISP programs still run in Common Lisp
http://www.informati[...]
2015-05-13
[7]
웹사이트
Roots of "Yu-Shiang Lisp", Mail from Jon L White, 1982
https://www.cs.cmu.e[...]
[8]
웹사이트
Mail Index
http://cl-su-ai.lisp[...]
[9]
웹아카이브
Knee-jerk Anti-LOOPism and other E-mail Phenomena: Oral, Written, and Electronic Patterns in Computer-Mediated Communication, JoAnne Yates and Wanda J. Orlikowski., 1993
http://ccs.mit.edu/p[...]
2012-08-08
[10]
서적
Proceedings of the 1982 ACM symposium on LISP and functional programming - LFP '82
ACM
1982-08-15
[11]
웹사이트
Features of Common Lisp
http://random-state.[...]
2008-08-22
[12]
웹사이트
Unicode support
http://www.cliki.net[...]
2008-08-21
[13]
간행물
Technical Issues of Separation in Function Cells and Value Cells
http://www.nhplace.c[...]
1988-06
[14]
웹사이트
Common Lisp Hyperspec: Section 3.1.7
http://www.lispworks[...]
[15]
웹사이트
Common Lisp Hyperspec: Function FLOOR
http://www.lispworks[...]
[16]
웹사이트
Common Lisp Hyperspec: Accessor GETHASH
http://www.lispworks[...]
[17]
웹사이트
Let Over Lambda
http://letoverlambda[...]
[18]
서적
Practical Common Lisp
http://www.gigamonke[...]
Apress
2005-04-07
[19]
웹사이트
Design Patterns in Dynamic Programming
http://norvig.com/de[...]
[20]
웹사이트
Common-Lisp.net
http://common-lisp.n[...]
[21]
웹사이트
Common Lisp Open Code Collection
http://clocc.sourcef[...]
[22]
웹사이트
32.6. Quickstarting delivery with CLISP
http://clisp.cons.or[...]
[23]
웹사이트
Armed Bear Common Lisp
http://common-lisp.n[...]
[24]
웹사이트
Corman Lisp sources are now available
http://lispblog.xach[...]
2015-01-05
[25]
웹사이트
History and Copyright
http://sbcl.sourcefo[...]
[26]
웹사이트
Platform Table
http://www.sbcl.org/[...]
[27]
웹사이트
Which programs are fastest? – Computer Language Benchmarks Game
https://web.archive.[...]
2013-05-20
[28]
웹사이트
Package: lang/lisp/impl/bbn/
https://www.cs.cmu.e[...]
[29]
웹사이트
Recent Developments in Butterfly Lisp, 1987, AAAI Proceedings
http://www.aaai.org/[...]
[30]
간행물
CLICC: A New Approach to the Compilation of Common Lisp Programs to C
1992-06-22
[31]
웹사이트
codemist.co.uk
http://lisp.codemist[...]
[32]
웹사이트
Axiom, the 30 year horizon, page 43
http://www.axiom-dev[...]
[33]
웹사이트
Golden Common Lisp Developer
http://www.goldhill-[...]
[34]
문서
Golden Common LISP: A Hands-On Approach, David J. Steele, June 2000 by Addison Wesley Publishing Company
[35]
간행물
L – A Common Lisp for Embedded Systems
1995-06-22
[36]
웹사이트
TI Explorer Programming Concepts
http://bitsavers.tra[...]
[37]
웹사이트
TI Explorer Lisp Reference
http://bitsavers.tra[...]
[38]
웹사이트
Medley Lisp Release Notes
http://bitsavers.tra[...]
[39]
웹사이트
Symbolics Common Lisp Dictionary
http://bitsavers.tra[...]
[40]
웹사이트
Symbolics Common Lisp Language Concepts
http://bitsavers.tra[...]
[41]
웹사이트
Symbolics Common Lisp Programming Constructs
http://bitsavers.tra[...]
[42]
웹사이트
SubL Reference – Cycorp
http://www.cyc.com/d[...]
[43]
웹사이트
Top Level Inc. – Software Preservation Group
http://www.softwarep[...]
[44]
간행물
WCL: Delivering efficient Common Lisp applications under Unix, Proceedings of the 1992 ACM conference on LISP and functional programming
http://dl.acm.org/ci[...]
[45]
웹사이트
commonlisp.net :: WCL
https://web.archive.[...]
2016-03-25
[46]
웹사이트
Package: lang/lisp/impl/xlisp/
https://www.cs.cmu.e[...]
[47]
웹사이트
Beating the Averages
http://www.paulgraha[...]
[48]
웹사이트
Authorizer's Assistant
http://www.aaai.org/[...]
[49]
웹archive
American Express Authorizer's Assistant
http://www.prenhall.[...]
2009-12-12
[50]
Webarchive
Real-time Application Development
http://www.gensym.co[...]
Gensym
2016-08-02
[51]
웹사이트
Genworks GDL
http://www.genworks.[...]
[52]
웹사이트
Opusmodus – Home
https://opusmodus.co[...]
[53]
Webarchive
PWGL – Home
http://www2.siba.fi/[...]
2011-05-03
[54]
웹사이트
Aerospace – Common Lisp
http://lisp-lang.org[...]
[55]
웹사이트
Piano Users, retrieved from manufacturer page
http://www.lissys.de[...]
[56]
웹사이트
Grammarly.com, Running Lisp in Production
https://tech.grammar[...]
2015-06-26
[57]
웹사이트
Remote Agent
https://ti.arc.nasa.[...]
[58]
웹사이트
Lisping at JPL
http://www.flownet.c[...]
[59]
웹사이트
Franz Inc Customer Applications: NASA
https://franz.com/su[...]
[60]
문서
Spike Planning and Scheduling System
Stsci.edu
[61]
웹사이트
Franz Inc Customer Applications: Space Telescope Institute
https://franz.com/su[...]
[62]
웹사이트
How It All Started…AKA the Birth of the CLR
https://blogs.msdn.m[...]
2023-08-28
[63]
웹사이트
on lisp
https://web.archive.[...]
2019-05-11
[64]
웹사이트
Pgloader
https://pgloader.io/
[65]
웹사이트
Why is pgloader so much faster
https://tapoueh.org/[...]
2014-05-14
[66]
문서
ごくまれにclispとも。なおCLISPという実装が実在するので混同回避のためあまり用いられない
[67]
문서
一方で型nullは、オブジェクトNILを表す型である。
[68]
문서
このようなtypespecは、配列の型arrayのvalid type specifierである。
[69]
문서
CLHS: Type ATOM
http://clhs.lisp.se/[...]
[70]
문서
CLiki : Unicode support
http://www.cliki.net[...]
[71]
문서
value cell
[72]
문서
function cell
[73]
문서
cons
[74]
문서
cons cell
[75]
문서
pair
[76]
문서
export
[77]
문서
instance
[78]
문서
declaration
[79]
문서
docstring
[80]
웹사이트
Technical Issues of Separation in Function Cells and Value Cells
http://www.nhplace.c[...]
[81]
문서
condition
[82]
문서
class
[83]
문서
metaclass
[84]
문서
binding
[85]
문서
Scheme
[86]
문서
nil
[87]
웹사이트
3.1 Evaluation
http://www.lispworks[...]
[88]
웹사이트
32.6. Quickstarting delivery with CLISP
http://clisp.cons.or[...]
[89]
웹사이트
History and Copyright - Steel Bank Common Lisp
http://sbcl.sourcefo[...]
[90]
문서
최근, 인터프리터의 지원도 시험적으로 구현되고 있다.
[91]
웹사이트
Clozure CL History
http://ccl.clozure.c[...]
[92]
웹사이트
http://trac.clozure.[...]
[93]
웹사이트
http://armedbear.org[...]
[94]
웹사이트
http://www.gnu.org/s[...]
[95]
웹사이트
http://www.digitool.[...]
[96]
웹사이트
http://jatha.sourcef[...]
[97]
웹사이트
http://www.cormanlis[...]
[98]
웹사이트
https://github.com/s[...]
[99]
웹사이트
http://www.franz.com[...]
[100]
웹사이트
http://www.lispworks[...]
[101]
웹사이트
http://www.scieneer.[...]
[102]
웹사이트
http://www.stsci.edu[...]
[103]
웹사이트
http://ic.arc.nasa.g[...]
[104]
웹사이트
Beating the Averages
http://www.paulgraha[...]
폴・그레엄
[105]
웹사이트
http://all-things-an[...]
[106]
웹사이트
ページ下部,開発者のコメント
http://dwave.wordpre[...]
[107]
웹사이트
http://www.dwavesys.[...]
[108]
웹사이트
http://www.itasoftwa[...]
[109]
웹사이트
http://www.izware.co[...]
[110]
웹사이트
http://www.izware.co[...]
[111]
웹사이트
http://www.piano.aer[...]
[112]
웹사이트
http://www.xanalys.c[...]
[113]
웹사이트
http://www.genworks.[...]
[114]
웹사이트
http://www.noteheads[...]
[115]
웹사이트
http://compo.sourcef[...]
[116]
웹사이트
http://lisa.sourcefo[...]
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com