존 매카시, 리습, 그리고 상징적 AI 설계의 뿌리
존 매카시의 기호 기반 접근과 리습의 설계(리스트, 재귀, 가비지 컬렉션)가 어떻게 AI와 현대 프로그래밍에 영향을 미쳤는지 살펴봅니다.

맥카시와 리습이 여전히 중요한 이유
이 글은 ‘구식 AI’의 박물관 투어가 아닙니다. 프로그래머, 테크 리드, 제품 담당자 등 소프트웨어를 만드는 누구에게든 실용적인 역사 수업입니다. 존 매카시의 아이디어는 우리가 프로그래밍 언어의 목적을 어떻게 생각하는지에 큰 영향을 미쳤기 때문입니다.
리습은 단순히 새로운 문법이 아니었습니다. 소프트웨어가 아이디어(숫자뿐 아니라)를 조작할 수 있다는 데 베팅했고, 언어 설계 선택이 연구, 제품 반복, 그리고 전체 툴링 생태계를 가속화할 수 있다는 가정이었습니다.
매카시의 유산을 읽는 유용한 방법은 오늘날에도 중요한 질문으로 보는 것입니다: 우리는 의도를 보일러플레이트, 마찰, 또는 우발적 복잡성에 빠지지 않고 얼마나 직접적으로 실행 가능한 시스템으로 바꿀 수 있는가? 이 질문은 Lisp의 REPL에서부터 현대의 ‘챗-투-앱’ 워크플로우까지 울려 퍼집니다.
존 매카시의 큰 아이디어: 추론을 프로그래밍 가능하게 만들기
존 매카시는 AI라는 연구 분야를 시작하는 데 기여한 것으로 기억되지만, 그가 강조한 것은 특정한 종류의 AI였습니다: 단순히 답을 계산하는 것뿐 아니라 아이디어를 조작할 수 있는 시스템. 1950년대 중반 그는 다트머스 여름 연구 프로젝트를 조직했고(그곳에서 ‘인공지능’이라는 용어가 제안됨) 이후 MIT와 스탠퍼드에서 AI 작업을 형성했습니다. 그러나 그의 가장 지속적인 기여는 그가 계속해서 던진 질문일지도 모릅니다: 추론 자체를 프로그램으로 표현할 수 있다면 어떨까?
숫자에서 기호로
초기의 많은 컴퓨팅 성공은 숫자 중심이었습니다: 탄도표, 공학 시뮬레이션, 최적화, 통계. 이런 문제들은 산술에 깔끔하게 맞았습니다.
매카시는 다른 것을 겨냥했습니다. 인간의 추론은 종종 ‘만약’, ‘때문에’, ‘속한다’, ‘종류다’, ‘이 조건을 만족하는 모든 것’ 같은 개념으로 작동합니다. 이런 것들은 부동소수점 값으로 자연스럽게 표현되지 않습니다.
매카시의 접근은 지식을 기호(이름, 관계, 분류)로 보고, 사고를 그 기호들에 대한 규칙 기반 변환으로 다루는 것이었습니다.
고수준으로 보면: 숫자 기반 접근은 “얼마나?”를 묻고, 기호 기반 접근은 “이것은 무엇인가?”와 “우리가 아는 것으로부터 무엇이 도출되는가?”를 묻습니다.
작업에 맞춘 도구, 리습
추론을 프로그래밍할 수 있다고 믿는다면, 규칙, 논리 문장, 중첩된 관계 같은 표현을 편하게 다루고 처리할 수 있는 언어가 필요합니다.
리습은 그 목표를 위해 만들어졌습니다. 아이디어를 엄격하고 미리 정해진 데이터 구조에 억지로 맞추는 대신, 리습은 코드와 지식을 비슷한 모양으로 표현하는 것을 자연스럽게 했습니다. 이 선택은 학문적 스타일이 아니라 실용적 다리였습니다: 생각을 기술하는 것과 절차를 실행하는 것 사이의 다리로, 매카시가 AI가 건너야 한다고 본 바로 그것입니다.
기호적 사고, 평이한 언어로
매카시와 초기 AI 연구자들이 ‘기호적(symbolic)’이라고 했을 때, 그들은 신비한 수학을 의미한 것이 아닙니다. 기호는 단순히 의미 있는 레이블입니다: customer 같은 이름, hungry라는 단어, IF와 THEN 같은 태그. 기호는 프로그램이 아이디어(분류, 관계, 규칙)를 숫자만으로가 아니라 직접 다루게 해 줍니다.
간단한 비유: 스프레드시트는 열과 산술이 중심인 세계에 강합니다. 기호적 시스템은 규칙, 분류, 예외, 구조가 중심인 세계에 강합니다.
의도를 담은 이름들
많은 프로그램에서 42와 "age"의 차이는 데이터 타입 그 자체보다 그 값이 무엇을 나타내는지입니다. 기호는 의미를 잃지 않고 비교하고 저장하고 결합할 수 있는 무언가를 제공합니다.
그래서 “파리는 도시다” 또는 “배터리가 낮다면 충전기를 찾아라” 같은 것을 표현하기 자연스럽습니다.
부분으로 이루어진 것을 위한 가장 단순한 구조, 리스트
기호로 쓸모 있는 일을 하려면 구조가 필요합니다. 리습은 아주 단순한 구조인 리스트를 대중화했습니다. 리스트는 단지 항목들의 순서 있는 묶음이고, 그 항목들 자체가 다시 리스트일 수 있습니다. 이 한 가지 아이디어로 문장, 폼, 트리 형태의 지식을 표현할 수 있습니다.
작은 개념 예시(리습 스타일):
(sentence (subject robot) (verb needs) (object power))
거의 영어처럼 읽힙니다: 주어, 동사, 목적어로 이루어진 문장. 구조화되어 있으므로 프로그램은 (subject robot)을 골라내거나 (object power)를 다른 것으로 바꿀 수 있습니다.
구조에서 추론으로: 규칙, 플래닝, 탐색
정보가 기호적 구조로 들어가면 고전적 AI 과제들이 접근 가능해집니다:
- 규칙: 패턴이 일치하면(
IF) 새로운 것을 결론짓는다(THEN). - 플래닝: 목표와 행동을 리스트로 표현하고 목표에 도달하도록 행동을 연결한다.
- 탐색: 가능한 기호 조합(상태)을 탐색하여 해법을 찾는다.
핵심 변화는 프로그램이 단순히 계산하는 것이 아니라 의미 있는 지식 조각들을 검사하고 변형할 수 있다는 점입니다.
언어 설계 선택이 수십 년간 울려 퍼지는 이유
리습의 설계 결정은 학계에만 머무르지 않았습니다. 그것들은 사람들이 도구를 만드는 방식과 아이디어를 얼마나 빨리 탐색할 수 있는지에 영향을 주었습니다:
- 표현력: 구조화된 지식을 표현하고 변형하는 것이 자연스러웠습니다.
- 빠른 반복: 대화형 개발은 ‘생각’과 ‘시도’ 사이의 루프를 단축했습니다.
- 확장성: 언어는 새로운 추상화를 만드는 쪽으로 장려했습니다.
이 특성들은 실험 비용을 낮추고 프로토타입이 제품으로 더 빨리 전환되며 팀이 요구사항 변화에 적응하기 쉬운 생태계를 만듭니다.
리습의 설계 목표
리습은 매우 실용적인 설계 문제에서 출발했습니다: 기호를 숫자처럼 자연스럽게 다루는 프로그램을 어떻게 쓸 것인가?
매카시는 ‘더 나은 계산기’를 만들려던 것이 아니었습니다. 그는 (is (parent Alice Bob)) 같은 표현을 (+ 2 3)만큼 쉽게 저장하고 검사하고 변형하고 논리적으로 다루기를 원했습니다.
기호 데이터에 맞춘 언어
우선순위는 기호 정보를 표현하고 조작하기 쉽게 만드는 것이었습니다. 그래서 리스트와 트리 같은 구조에 초점이 맞춰졌습니다. 이는 인간이 의미를 표현할 때 이미 사용하는 형태: 문장, 논리 규칙, 중첩된 분류와 관계에 잘 맞습니다.
유연성을 여는 단순성
또 다른 목표는 언어의 핵심을 작게 그리고 일관되게 유지하는 것이었습니다. 핵심에 특수 사례가 적을수록 규칙을 외우는 시간이 줄고 아이디어를 합성하는 데 더 많은 시간을 쓸 수 있습니다. 리습은 더 큰 추상화를 만들 수 있는 작은 빌딩 블록 집합에 기대었습니다.
데이터처럼 생긴 프로그램
핵심 통찰은 프로그램과 데이터가 같은 구조를 공유할 수 있다는 것입니다. 간단히 말해: 데이터가 중첩된 리스트라면 프로그램도 중첩된 리스트일 수 있습니다.
그 결과 당신은:
- 프로그램을 생성하고(구조화된 데이터로서)
- 그것을 수정하고(다른 데이터처럼)
- 실행할 수 있습니다
언어 설계에서의 문화적 변화
리습은 또한 언어가 모두에게 하나의 정답일 필요는 없다는 사고방식을 대중화했습니다. 언어는 추론, 탐색, 지식 표현 같은 문제 영역을 중심으로 설계될 수 있고, 그럼에도 불구하고 수십 년 동안 범용 프로그래밍에 영향을 미칠 수 있다는 것입니다.
S-표현식: 단순한 구조, 큰 영향
S-표현식(기호 표현식)은 리습의 대표 아이디어입니다: 코드와 데이터를 중첩된 리스트로 표현하는 단일 일관된 방식.
한눈에 보면 S-표현식은 항목들을 감싸는 괄호입니다—어떤 항목은 원자(이름과 숫자 같은)이고 어떤 항목은 다시 리스트입니다. ‘리스트 안의 리스트’ 규칙이 핵심입니다.
모든 것을 위한 하나의 형태
구조가 균일하기 때문에 리습 프로그램은 바닥부터 동일한 빌딩 블록으로 구성됩니다. 함수 호출, 설정 같은 데이터 조각, 프로그램 구조의 일부가 모두 리스트로 표현될 수 있습니다.
이 일관성의 장점:
- 구문 분석이 단순해집니다: 언어는 많은 특수 사례를 가질 필요가 없습니다.
- 코드 변환이 실용적입니다: 리스트 트리를 걷고 부분을 다시 쓸 수 있습니다.
- 평가가 규칙적입니다: 많은 구성 요소가 같은 형태를 공유하므로 평가기가 일관되게 다룰 수 있습니다.
리습을 직접 쓰지 않더라도 한 가지 교훈은 분명합니다: 시스템이 하나 또는 두 가지 예측 가능한 형태로 구성되면 엣지 케이스와 싸우는 시간이 줄고 실제로 쌓는 시간이 늘어납니다.
조합의 감각
S-표현식은 작은 읽기 쉬운 조각들이 자연스럽게 더 큰 것으로 결합되게 장려합니다. 프로그램이 ‘그저 중첩된 리스트’라면 아이디어를 결합하는 것은 종종 한 표현을 다른 표현 안에 중첩하거나 재사용 가능한 부분으로 리스트를 조립하는 것을 의미합니다.
이것은 모듈식 스타일로 유도합니다: 하나의 일을 하는 작은 연산을 작성하고 그것들을 쌓아 더 큰 의도를 표현합니다.
단점: 괄호
눈에 띄는 단점은 낯설다는 것입니다. 많은 신입에게 괄호가 많은 문법은 이상하게 보입니다.
하지만 장점은 예측 가능성입니다: 중첩 규칙을 이해하면 프로그램 구조를 신뢰성 있게 파악할 수 있고, 도구들도 마찬가지입니다. 이 명료함은 S-표현식이 리습을 넘어선 결과를 낳은 큰 이유입니다.
재귀와 리스트 처리: 핵심 빌딩 블록
재귀는 일상적인 비유로 이해하기 쉽습니다: 어지러운 방을 더 작은 ‘방’들로 나누면서 정리하는 것. 한 번에 모든 것을 해결하려 하지 않습니다. 물건 하나를 집어 제자리에 놓고 남은 부분에 같은 동작을 반복합니다. 단계는 단순하지만, 남은 것이 없을 때까지 반복하는 힘이 있습니다.
리습은 데이터의 많은 부분이 자연스럽게 리스트로 구성되기 때문에 이 아이디어에 기대었습니다: 리스트는 ‘첫 번째 항목’과 ‘나머지’라는 형태를 가지므로 재귀적 사고에 완벽히 맞습니다.
리스트를 처리하려면 첫 요소를 처리한 다음 나머지에 같은 로직을 적용합니다. 리스트가 비어 있으면 멈춥니다—이것이 재귀가 신비로워 보이지 않고 잘 정의된 이유입니다.
개념적 예시: 리스트 합산
숫자들의 리스트 합을 구한다고 가정합시다.
- 리스트가 비어 있으면 합은 0입니다.
- 그렇지 않으면 합은 첫 번째 숫자에 나머지의 합을 더한 것입니다.
정의가 영어처럼 읽히고 프로그램 구조가 그 아이디어를 반영합니다.
트리를 걷는 사고
기호적 AI는 표현을 트리 구조(연산자와 하위 표현)로 나타내는 경우가 많습니다. 재귀는 그 트리를 ‘걷는’ 자연스러운 방법입니다: 왼쪽 부분을 평가하는 방식을 오른쪽 부분에도 적용하고, 단순 값에 도달할 때까지 계속합니다.
이 패턴들은 이후의 함수형 프로그래밍을 형성하는 데 기여했습니다: 작은 함수들, 명확한 기본 사례, 그리고 추론하기 쉬운 데이터 변환들. 리습 밖에서도 ‘한 단계 수행하고 남은 것에 반복’하는 습관은 더 깨끗한 코드와 숨겨진 부작용의 감소로 이어집니다.
가비지 컬렉션: 단순한 세부 사항이 아닌 생산성 기능
초기 프로그래머들은 종종 메모리를 수동으로 관리해야 했습니다: 공간을 할당하고 누가 그것을 소유하는지 추적하며 적절한 순간에 해제하는 것을 기억해야 했습니다. 그 작업은 개발 속도를 늦출 뿐만 아니라 특정 유형의 재현하기 어려운 버그를 만듭니다: 성능을 서서히 저하시킨 누수와 원래 실수 이후에 프로그램을 충돌시키는 댕글링 포인터.
가비지 컬렉션이 하는 일(평이한 설명)
존 매카시는 리습을 위해 가비지 컬렉션을 도입하여 프로그래머들이 장부 정리보다 의미에 집중하게 만들고자 했습니다.
높은 수준에서 가비지 컬렉션(GC)은 실행 중인 프로그램에서 더 이상 도달할 수 없는 메모리 조각들—아무도 다시 사용할 수 없는 값들—을 찾아 그 공간을 회수합니다.
“모든 객체를 정확히 한 번 해제했는가?”를 묻는 대신, GC는 “이 객체에 아직 접근할 수 있는가?”를 묻습니다. 프로그램이 접근할 수 없다면 그것은 쓰레기로 간주됩니다.
왜 이것이 생산성에 관한 이야기인가
기호적 AI 작업에서 리습 프로그램은 자주 많은 단명 리스트, 트리, 중간 결과를 만들어냅니다. 수동 메모리 관리는 실험을 자원 정리에 대한 지속적인 전투로 바꿔 놓습니다.
GC는 일상 경험을 변화시킵니다:
- 빠른 반복: 메모리 전략을 먼저 설계하지 않고도 자유롭게 프로토타입을 만들 수 있습니다.
- 충돌 가능성 감소: 포인터 관련 실패 범주가 줄어듭니다.
- 더 깔끔한 코드: 함수는 누구가 무엇을 해제해야 하는지에 대한 숨겨진 계약 없이 새 구조를 반환할 수 있습니다.
핵심 아이디어는 언어 기능이 팀 배가기가 될 수 있다는 점입니다: 원인 불명의 손상 디버깅에 쓰는 시간이 줄어들면 실제 로직 개선에 더 많은 시간을 쓸 수 있습니다.
장기적 영향
매카시의 선택은 리습 안에만 머무르지 않았습니다. 많은 이후 시스템이 GC(그 변형들)를 채택했습니다: Java, C#, Python, JavaScript 런타임, Go 등이 모두 대규모 개발을 더 안전하고 빠르게 만들기 위해 가비지 컬렉션에 의존합니다—성능이 중요한 경우에도 마찬가지입니다.
평가와 매크로: 내부에서 언어를 확장하기
‘평가(evaluation)’가 의미하는 것(전문 용어 없이)
리습에서 표현식은 일관된 형태(종종 리스트)로 작성된 코드 조각입니다. 평가는 그 표현식이 무엇을 의미하는지 그리고 무엇을 생산하는지 결정하는 과정입니다.
예를 들어 “이 숫자들을 더해라” 또는 “이 입력으로 이 함수를 호출하라”고 쓸 때, 평가기는 그 표현식을 결과로 바꾸기 위해 작은 규칙 집합을 따릅니다. 심판관처럼 어떤 것을 언제 수행하고 언제 멈출지를 결정합니다.
작고 일관된 평가기가 주는 힘
매카시의 핵심적인 움직임은 단순히 새 문법을 발명한 것이 아니라 ‘의미 엔진’을 작고 규칙적이게 유지한 것입니다. 평가기가 몇 가지 명확한 규칙으로 구성되면 좋은 일이 두 가지 일어납니다:
- 언어를 이해하기 쉬워집니다—수십 개의 특수 사례를 다루지 않아도 됩니다.
- 시스템 전체를 다시 쓰지 않고도 언어를 확장할 수 있습니다. 새 기능은 기존 것을 사용해 표현 가능하기 때문입니다.
이 일관성은 리습이 기호적 AI 실험의 놀이터가 된 이유 중 하나입니다: 연구자들은 컴파일러 팀이 언어를 재설계할 때까지 기다리지 않고도 새로운 표현과 제어 구조를 빠르게 시도할 수 있었습니다.
매크로: 코드 패턴의 자동화
매크로는 반복되는 코드 형태를 자동화하는 리습의 방법입니다. 함수가 계산을 반복하지 않게 도와주듯, 매크로는 구조적 반복을 제거합니다—예: “X를 수행하되 동시에 로깅도 하라” 또는 “규칙을 위한 미니 DSL을 정의하라”.
실용적 효과는 리습 안에서 새로운 편의 기능을 성장시킬 수 있다는 점입니다. 많은 현대 도구들이 이 아이디어를 반향합니다—템플릿 시스템, 코드 생성기, 메타프로그래밍 기능 등—이들은 같은 목표를 지원합니다: 더 빠른 실험과 더 명확한 의도.
관심이 있다면 이 사고방식이 일상 개발 워크플로에 어떻게 영향을 주었는지 /blog/the-repl-and-fast-feedback-loops를 보세요.
REPL과 빠른 피드백 루프
리습의 매력은 단순히 언어 자체가 아니라 그것으로 작업하는 방식에도 있었습니다. 리습은 REPL을 대중화했습니다: 읽기–평가–출력 루프(Read–Eval–Print Loop). 일상적으로 말하자면, 컴퓨터와 대화하는 것과 같습니다. 표현식을 입력하면 시스템이 즉시 실행하고 결과를 출력한 뒤 다음 입력을 기다립니다.
평이한 워크플로
전체 프로그램을 쓰고 컴파일하고 실행한 뒤 무엇이 잘못됐는지 찾는 대신, 작은 단계로 아이디어를 시도할 수 있습니다. 함수를 정의하고, 몇 가지 입력으로 테스트하고, 수정하고, 다시 테스트—모두 몇 초 내에 가능합니다.
그 리듬은 실험을 장려합니다. 초기 AI 작업에서는 올바른 접근법을 모르는 경우가 많았기 때문에 특히 중요했습니다.
빠른 피드백이 결과를 바꾸는 이유
빠른 피드백은 ‘큰 베팅’을 ‘작은 확인’으로 바꿉니다. 연구에선 가설을 탐색하고 중간 결과를 검사하기 쉬워집니다.
제품 프로토타이핑에서는 반복 비용을 줄입니다: 실제 데이터로 동작을 검증하고, 엣지 케이스를 빨리 발견하며, 긴 빌드 사이클을 기다리지 않고 기능을 다듬을 수 있습니다.
이것이 현대의 바이브 코딩 도구들이 매력적인 이유이기도 합니다: 이들은 본질적으로 피드백 루프를 강하게 압축한 것입니다. 예를 들어 Koder.ai는 채팅 인터페이스(에이전트 기반 아키텍처 사용)를 통해 제품 의도를 빠르게 웹/백엔드/모바일 코드로 바꾸어 ‘시도 → 조정 → 재시도’ 루프를 REPL에 더 가깝게 느껴지게 합니다.
이미 알고 있는 현대적 등가물
REPL 아이디어는 오늘날 다음과 같은 곳에서 나타납니다:
- Python/Node 대화형 셸
- Jupyter 및 기타 노트북
- 브라우저 개발자 도구 콘솔
- 웹 앱의 ‘라이브 리로드’와 핫 모듈 교체
도구는 다르지만 원칙은 같습니다: 생각과 결과 사이의 거리를 줄이세요.
대화형 개발이 가장 도움되는 경우
요구사항이 불확실하고, 데이터 중심 기능을 탐색하거나, API를 설계하거나, 까다로운 로직을 디버깅하는 팀은 REPL류 워크플로의 혜택을 가장 크게 봅니다. 작업이 학습 중심이라면(interacting with users, data, or edge cases), 대화형 피드백은 사치가 아니라 배가기입니다.
리습 아이디어가 프로그래밍 전반에 퍼진 방식
리습이 ‘모두의 일상 문법’이 되지는 않았지만, 아이디어를 뿌려 놓아 많은 생태계에서 통상적인 것으로 자리 잡게 했습니다.
일상 코드의 함수형 패턴
리습이 기본으로 삼았던 개념들—값으로서의 함수, 고차 연산의 광범위한 사용, 작은 조각을 합성해 프로그램을 만드는 선호—이제 널리 보입니다. 리습과 전혀 닮지 않은 언어도 map/filter 스타일 변환, 불변 데이터 습관, 반복자나 폴드로 표현되는 재귀적 사고를 장려합니다.
핵심 변화는 사고 방식입니다: 데이터 변환을 파이프라인으로 처리하고 행동을 전달 가능한 것으로 취급하세요.
기호적 표현: AI에서 컴파일러 및 툴링으로
리습은 프로그램을 데이터로 표현하기 쉽게 만들었습니다. 이 사고방식은 오늘날 컴파일러, 포매터, 린터, 코드 생성기가 AST(추상 구문 트리)를 다루는 방식에 나타납니다. AST를 다뤄본 적이 있다면, 그것은 ‘코드를 데이터로’ 다루는 근사한 활동입니다—구조가 JSON 객체든 타입화된 노드든 바이트코드 그래프든.
같은 기호적 접근은 구성 자동화: 설정 형식, 템플릿 시스템, 빌드 파이프라인 모두 도구가 검사하고 변형하고 검증할 수 있는 구조화된 표현에 의존합니다.
DSL과 재작성 없이 확장하기
현대의 리습 계열 언어들(넓은 의미에서)은 내부 DSL을 설계하는 방식에 계속 영향을 줍니다—테스트, 배포, 데이터 정리, UI용 소규모 맞춤 언어 등.
리습 밖에서도 매크로 시스템, 메타프로그래밍 라이브러리, 코드 생성 프레임워크는 동일한 목표를 지향합니다: 문제에 맞게 언어를 확장하되 전체를 다시 쓰지 않기.
실용적 결론: 문법 선호는 변하지만 지속적인 아이디어들—기호적 구조, 합성 가능한 함수, 확장성—은 수십 년과 코드베이스를 넘어 계속 가치가 있습니다.
리습에 대한 트레이드오프와 오해
리습은 ‘명석하다’와 ‘읽기 어렵다’ 사이를 오가는 평판이 있습니다. 종종 간접 경험에 기반한 인상입니다. 진실은 평범합니다: 리습은 적절한 상황에서 강력하고 다른 상황에서는 불편한 선택을 합니다.
“괄호가 너무 많다”(가독성 문제)
초보자에게 리습의 균일한 문법은 프로그램의 ‘내부’를 보는 것처럼 느껴질 수 있습니다. 이 불편함은 현실입니다, 특히 구문이 다른 언어에 익숙하다면 더욱 그렇습니다.
역사적으로 보면 리습의 구조는 요점이기도 했습니다: 코드와 데이터가 같은 모양을 공유하므로 프로그램을 변형하고 생성하고 분석하기 쉬웠습니다. 편집기 지원(들여쓰기, 구조적 탐색)이 있으면 리습 코드는 종종 괄호를 세는 대신 형태로 읽힙니다.
성능: 신화, 역사, 현재의 현실
리습이 본질적으로 느리다는 고정관념이 있습니다. 역사적으로 일부 구현은 저수준 언어에 비해 고전적 어려움을 겪었고 동적 특성은 오버헤드를 더했습니다.
하지만 ‘리습’ 전체를 하나의 성능 프로필로 취급하는 것은 정확하지 않습니다. 많은 리습 시스템은 오랫동안 컴파일, 타입 선언, 진지한 최적화를 지원해 왔습니다. 더 유용한 관점은: 메모리 레이아웃, 예측 가능한 지연 시간, 원시 처리량에 대해 얼마나 많은 제어가 필요한가이며 당신의 리습 구현이 그 요구를 충족하는가입니다.
생태계와 채용: 실용적 제약
공정한 비판 중 하나는 생태계 적합성입니다. 리습 방언과 도메인에 따라 라이브러리, 툴링, 인력 풀이 주류 스택보다 작을 수 있습니다. 빠르게 광범위한 팀으로 출하해야 한다면 이것이 언어의 우아함보다 더 중요한 문제가 될 수 있습니다.
균형 잡힌 결론
고정관념으로 리습을 판단하지 말고 그 기본 아이디어들—균일한 구조, 대화형 개발, 도메인 특화 추상화를 위한 매크로—을 독립적으로 평가하세요. 리습을 쓰지 않더라도 이 개념들은 언어 설계와 코드 작성 방식에 날카로움을 더합니다.
언어 설계와 일상 코딩을 위한 실용적 시사점
매카시는 단지 역사적 언어를 남긴 것이 아니라, 소프트웨어를 더 쉽게 바꾸고 설명하고 확장하게 만드는 습관을 남겼습니다.
훔쳐갈 만한 6가지 교훈
-
교묘한 표면보다 단순한 핵심을 선호하라. 직교적인 작은 빌딩 블록은 배우기 쉽고 깨뜨리기 어렵습니다.
-
데이터 형태를 균일하게 유지하라. 많은 것이 같은 표현을 공유하면 프린터, 디버거, 직렬화기, 변환기를 재사용할 수 있어 도구가 단순해집니다.
-
필요할 때 프로그램을 데이터로(데이터를 프로그램처럼) 다뤄라. 구조를 검사하고 변형할 수 있다면 안전한 리팩터링, 마이그레이션, 코드 생성기를 만들 수 있습니다.
-
지루한 일을 자동화하라. 가비지 컬렉션이 고전적 예이지만 넓은 관점은 실수를 예방하는 자동화에 투자하라는 것입니다.
-
피드백 루프를 최적화하라. 대화형 평가(REPL 스타일)는 작은 실험, 빠른 검증, 행동에 대한 더 나은 직관을 장려합니다.
-
확장을 1등 시민으로 설계하라. 리습 매크로는 한 가지 해법일 뿐입니다; 다른 생태계에서는 플러그인, 템플릿, DSL, 컴파일타임 변환이 같은 역할을 합니다.
10분 짜리 작은 연습
라이브러리나 아키텍처를 선택하기 전에 실제 기능—예: “할인 규칙” 또는 “지원 티켓 라우팅”—을 하나 골라 트리로 그려보세요. 그런 다음 그 트리를 중첩된 리스트(또는 JSON)로 다시 작성하세요. 노드와 리프는 무엇인지, 어떤 변환이 필요한지 적어보세요.
어떤 스택에서도 리습 아이디어를 도입하기
리습이 아니더라도 다음 사고방식을 채택할 수 있습니다: AST 같은 표현을 만들고, 반복적인 글루 코드에 대해 코드 생성을 사용하며, 데이터 우선 파이프라인(파싱 → 변환 → 평가)을 표준으로 삼으세요. 많은 팀이 중간 표현을 명시적으로 만드는 것만으로도 이점을 얻습니다.
REPL 원칙이 좋지만 주류 스택에서 제품 기능을 출시한다면 도구에서 그 정신을 빌려올 수 있습니다: 빠른 반복 루프, 스냅샷/롤백, 그리고 실행 전에 명시적 계획을 도입하세요. 예를 들어 Koder.ai는 계획 모드와 스냅샷/롤백을 포함해 빠른 반복을 더 안전하게 만드는 운영적 반향을 제공합니다.
매카시의 지속적 영향은 이렇습니다: 우리가 추론 자체를 프로그래밍 가능하게 만들고 아이디어에서 실행 가능한 시스템으로 가는 경로를 최대한 직접적으로 유지할수록 프로그래밍은 더 강력해집니다.
자주 묻는 질문
“기호적 사고”는 실무적으로 무엇을 의미하나요?
기호적 사고는 개념과 관계를 직접적으로 표현하고(예: “고객”, “is-a(상속)”, “depends-on(의존)”, “if…then…”), 그런 표현들에 규칙과 변환을 적용합니다.
숫자 연산이 핵심인 문제가 아니라 구조, 예외, 의미가 많은 문제(규칙 엔진, 플래닝, 컴파일러, 설정, 워크플로우 로직)에 가장 유용합니다.
칭호(“AI”)를 만든 것 이상으로 존 매카시의 핵심 기여는 무엇이었나요?
맥카시는 '추론을 프로그램으로 표현할 수 있다'는 관점을 강하게 밀어붙였습니다 — 단순한 계산이 아니라 추론 자체를 프로그램화하자는 생각입니다.
그 관점은 다음을 형성했습니다:
- 지식을 표현하는 방식(구조화된 기호)
- 해결책을 탐색하는 방식(탐색, 플래닝, 규칙 적용)
- 언어에 대한 기대(표현력, 확장성, 빠른 반복)
지식을 표현하는 데 왜 Lisp의 리스트가 중요한가요?
리스트는 ‘부분들로 이루어진 것’을 표현하는 최소한의 유연한 방법입니다. 리스트의 요소가 다시 리스트가 될 수 있기 때문에 자연스럽게 트리 구조가 만들어집니다.
이를 통해 다음이 쉬워집니다:
- 일부를 골라내기(예: “주어” 노드)
- 서브트리를 다시 쓰기(변환)
- 규칙과 표현식을 일관되게 모델링하기
S-표현식이란 무엇이고, 왜 중요한가요?
S-표현식은 코드와 데이터를 하나의 일관된 형태로 표현합니다: 중첩된 리스트.
그 일관성 덕분에 시스템은 단순해집니다:
- 구문 분석이 더 규칙적입니다
- 변환이 직관적입니다(트리를 걷고 노드를 다시 쓰기)
- 포맷터, 분석기, 생성기 같은 도구들이 동일한 표현을 재사용할 수 있습니다
매크로와 함수의 실용적 차이는 무엇인가요?
매크로는 반복되는 코드 구조를 자동화합니다. 단순한 계산을 재사용하는 함수와 달리, 매크로는 호출 지점의 구조를 생성하거나 변형합니다.
매크로를 쓸 때의 예:
- 규칙이나 테스트를 위한 작은 DSL 작성
- 공통 패턴(로깅, 타이밍, 계측) 강제
- 호출 지점의 보일러플레이트 제거
재사용 가능한 로직만 필요하면 함수가 더 적절합니다.
역사적으로 Lisp에서 가비지 컬렉션은 왜 생산성 기능으로 취급되었나요?
가비지 컬렉션(GC)은 더 이상 접근할 수 없는 메모리를 자동으로 회수합니다. 그 결과 다음과 같은 장점이 있습니다:
- 포인터 관련 버그(뎅글링 포인터, 중복 해제) 감소
- 많은 단명 객체(리스트/트리/중간 결과)를 생성하는 실험적 개발에 유리
즉, 생산성 향상을 위한 언어 기능으로 볼 수 있습니다: 리팩터링과 프로토타이핑에 드는 비용을 줄여줍니다.
REPL은 어떻게 소프트웨어 개발 방식을 바꾸나요?
REPL은 ‘읽기-평가-출력 루프(Read–Eval–Print Loop)’로, 컴퓨터와 대화하듯 짧은 사이클로 코드를 실행하고 결과를 확인하는 환경입니다.
비 Lisp 스택에서 같은 이점을 얻으려면:
- 대화형 셸/노트북 사용
- 빠른 테스트 실행과 워치 모드 도입
- 코드 근처에 예제와 픽스처 유지
관련 읽기: /blog/the-repl-and-fast-feedback-loops
Lisp의 아이디어는 어떻게 주류 프로그래밍에 퍼졌나요?
현대 워크플로우에 널리 퍼진 개념들:
- 함수형 파이프라인(
map/filter, 합성) - AST 기반 도구(린터, 포맷터, 코드 생성)
- DSL과 확장성(매크로, 템플릿, 플러그인)
- 대화형 탐색(노트북, 개발자 도구 콘솔)
직접 Lisp를 사용하지 않더라도 이 아이디어들은 일상적으로 쓰일 가능성이 큽니다.
Lisp에 대한 현실적인 단점과 오해는 무엇인가요?
타협과 오해들:
- 문법의 낯섦: 괄호가 많아 보이지만, 편집기 지원이 있으면 구조로 읽게 됩니다.
- 에코시스템/인력: 일부 Lisp 방언은 라이브러리와 채용 풀이 좁을 수 있습니다.
- 성능 편차: 모든 Lisp가 같은 성능을 내는 건 아닙니다. 구현에 따라 컴파일과 최적화를 지원합니다.
실무적 접근은 명성에 의존하지 말고 도메인과 제약 조건에 맞춰 평가하는 것입니다.
맥카시/리습의 교훈을 Lisp 없이 현대 코드베이스에 어떻게 적용할 수 있나요?
간단한 연습:
- 실제 기능(예: “할인 규칙”)을 고르세요.
- 그것을 트리로 그리세요(노드 = 개념/규칙, 리프 = 값/필드).
- JSON이나 리스트 형태의 중첩 데이터로 작성하세요.
- 필요 변환(검증, 재작성, 평가, 설명)을 적으세요.
이 과정은 ‘코드-같은-데이터’ 패턴이나 규칙 엔진, DSL 같은 해결책이 어디에 도움이 되는지 드러내 줄 것입니다.