정의
S‑표현식은 심볼리컬 식(symbolic expression)의 약어로, 주로 Lisp 계열 프로그래밍 언어에서 사용되는 자료 구조 및 표기법이다. 괄호 (와 ) 로 둘러싸인 원자(atom) 와 리스트(list) 로 구성되며, 코드와 데이터를 동일한 형태로 기술할 수 있는 동질성(homogeneity) 을 제공한다. 이러한 특성으로 인해 S‑표현식은 프로그램 자체를 데이터로 취급할 수 있는 코드‑데이터 동등성(code‑data equivalence) 을 구현하는 데 핵심적인 역할을 한다.
역사
- 1960년대: John McCarthy가 개발한 언어 Lisp에서 처음 도입하였다. 초창기 논문 “Recursive Functions of Symbolic Expressions and Their Computation by Machine”(1960) 에서 “S‑expression”이라는 용어가 등장한다.
- 1970~80년대: Scheme, Common Lisp, Clojure 등 다양한 Lisp 파생 언어가 S‑표현식을 표준 구문으로 채택하였다.
- 1990년대 이후: S‑표현식은 데이터 교환 포맷(예: EDN, Racket’s s‑expressions) 으로도 활용되며, 일부 인공 지능·형식 논리 분야에서도 메타데이터 기술에 사용된다.
구조와 문법
| 요소 | 설명 | 예시 |
|---|---|---|
| 원자(atom) | 더 이상 분해되지 않는 기본 단위. 숫자, 문자열, 심볼 등. | 42, "hello", foo |
| 리스트(list) | 원자 또는 다른 리스트들의 순서 있는 집합. 괄호로 둘러쌈. | (add 1 2), (if (> x 0) x (- x)) |
| 함수 호출 | 리스트의 첫 번째 원소가 함수(또는 연산자)이며, 뒤따르는 원소들은 인수. | (multiply 3 4) → 12 |
| 인용(quote) | 평가(evaluation)를 억제하고 그대로 데이터를 반환. ' 또는 (quote ...) 사용. |
'(+ 1 2) → (+ 1 2) |
| 구조적 정의 | 리스트 내에 또 다른 리스트를 중첩할 수 있어 복합 구조 표현이 가능. | (define (square x) (* x x)) |
- 공백(space, newline 등)은 토큰 구분자이며, 의미를 갖지 않는다.
- 주석은 Lisp 자체 문법에 따라
;로 시작해 행 끝까지 무시한다.
주요 특징
- 단일 구문
- 모든 프로그램 구조가 동일한 “리스트” 형태이므로 파서(parser)가 매우 단순한다.
- 동적 타이핑
- 원자는 런타임에 타입이 결정되며, 리스트 자체도 데이터와 코드 모두에 사용된다.
- 매크로 시스템
- 코드 자체를 조작·생성할 수 있는 강력한 매크로가 S‑표현식 기반 언어에서 자연스럽게 구현된다.
- 가독성
- 중첩된 괄호가 많아 초보자에게는 가독성이 떨어질 수 있지만, 구조가 명확해 논리적 흐름을 파악하기 쉬운 장점도 있다.
활용 분야
| 분야 | 적용 예시 |
|---|---|
| 프로그래밍 언어 구현 | Lisp, Scheme, Clojure, Racket 등 |
| 메타프로그래밍 | 매크로, 코드 생성, DSL 구현 |
| 구조적 데이터 교환 | EDN (Extensible Data Notation), Racket 데이터 파일 |
| 인공 지능·논리 프로그래밍 | Prolog‑like 논리 표현, 규칙 기반 시스템 |
| 구성 파일·스크립트 | Emacs Lisp 설정 파일(.emacs), Clojure deps.edn |
대표적인 예시
;; 기본적인 덧셈 함수 정의
(defun add (a b)
(+ a b))
;; 조건문과 재귀 호출
(defun factorial (n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))
;; 리스트 조작
(setq my-list '(1 2 3 4))
(push 0 my-list) ; (0 1 2 3 4)
파싱 방식
- 읽기(read) 단계: 문자열을 토큰(token)으로 분리하고, 괄호의 짝을 맞추어 추상 구문 트리(AST) 로 변환한다.
- 평가(eval) 단계: AST를 순회하면서 리스트의 첫 원소를 함수로 해석하고 인자를 평가한다.
- 대부분의 Lisp 구현은 재귀적 하향 파서(recursive‑descent parser) 혹은 스택 기반 파서 를 사용한다.
관련 용어
- 원자(atom) – 분해되지 않는 최소 단위.
- 리스트(list) – 원자 및 리스트의 순서 있는 집합.
- 매크로(macro) – 코드 자체를 변형·생성하는 메커니즘.
- 코드‑데이터 동등성(code‑data equivalence) – 프로그램 자체가 데이터와 동일한 구조를 갖는 특성.
참고문헌
- John McCarthy, “Recursive Functions of Symbolic Expressions and Their Computation by Machine”, Communications of the ACM, 1960.
- Paul Graham, On Lisp, 1993.
- Guy L. Steele Jr., The Common Lisp HyperSpec, 1996.
- Clojure Documentation, “Data Structures – Lists and Vectors”, 2023.
본 항목은 2026년 현재까지 알려진 학술·기술 자료를 토대로 작성되었습니다.