SDF 챕터들에서 추출한 핵심 개념: - additive-programming: 가산적 프로그래밍 (전체 관통 테마) - generic-procedures: 제네릭 프로시저 (Ch3, Ch5, Ch6) - combinators: 컴비네이터 (Ch2~Ch5) - partial-information: 부분 정보 (Ch1, Ch4, Ch6, Ch7) - degeneracy: 퇴화성 (Ch1, Ch7) - layered-data: 레이어드 데이터 + 의존성 추적 (Ch2, Ch3, Ch6, Ch7) - propagation: 전파 모델 (Ch1, Ch5, Ch6, Ch7) - domain-specific-language: DSL (Ch2~Ch5) wiki/index.md Concepts 섹션 등록, wiki/log.md 기록 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
133 lines
6.7 KiB
Markdown
133 lines
6.7 KiB
Markdown
---
|
|
title: 도메인 특화 언어 (DSL)
|
|
tags: [concept, SDF]
|
|
sources: [SDF-ch2-dsl, SDF-ch3-generic-procedures, SDF-ch4-pattern-matching, SDF-ch5-evaluation]
|
|
updated: 2026-04-30
|
|
---
|
|
|
|
# 도메인 특화 언어 (DSL)
|
|
|
|
## 한 줄 정의
|
|
|
|
문제 도메인의 개념과 관계를 직접 반영하는 어휘와 구조를 가진 언어로, 해당 도메인의 문제를 그 언어로 자연스럽게 표현할 수 있게 하여 도메인 전문가와 프로그래머 사이의 간격을 줄이고 가산적 확장을 가능하게 한다.
|
|
|
|
## 핵심 내용
|
|
|
|
### DSL의 스펙트럼
|
|
|
|
SDF에서 DSL은 단일한 기법이 아니라 구현 깊이에 따른 스펙트럼이다:
|
|
|
|
**1단계: 컴비네이터 기반 임베디드 DSL (Ch2)**
|
|
- 호스트 언어(Scheme) 함수들을 컴비네이터로 조합
|
|
- 별도의 파서 없음. 호스트 언어의 문법을 그대로 사용
|
|
- 예: 정규표현식 컴비네이터, 함수 컴비네이터
|
|
|
|
**2단계: 제네릭 프로시저 기반 도메인 언어 (Ch3)**
|
|
- 도메인의 연산(더하기, 곱하기)이 제네릭 프로시저
|
|
- 새 타입이 도입될 때마다 핸들러를 추가해 도메인을 확장
|
|
- 예: 숫자 → 기호 → 함수 → 미분 객체로 확장되는 산술
|
|
|
|
**3단계: 패턴 기반 규칙 언어 (Ch4)**
|
|
- 데이터 변환을 패턴+귀결 규칙으로 표현
|
|
- `rule-simplifier`가 고정점까지 규칙들을 자동 적용
|
|
- 예: 대수 단순화 규칙들, 체스 규칙
|
|
|
|
**4단계: 완전한 인터프리터 (Ch5)**
|
|
- 새 언어를 완전히 정의: 구문, 의미, 실행 모델
|
|
- 가장 강력하지만 가장 많은 투자가 필요
|
|
- 예: lazy eval, amb를 포함한 Scheme 인터프리터
|
|
|
|
### 왜 DSL인가
|
|
|
|
> "One of the best ways to attack a problem is to make up a domain-specific language in which the solution is easily expressed."
|
|
|
|
> "Programmers should know how to escape the confines of whatever programming language they must use by making an interpreter for a language that is more appropriate for expressing the solution."
|
|
|
|
범용 언어로 도메인 문제를 풀면 두 가지 불편이 생긴다:
|
|
1. **개념의 직접성 부재**: 도메인 개념을 언어 구조에 억지로 매핑해야 함
|
|
2. **가산성 어려움**: 새 개념이 추가될 때 기존 코드의 여러 곳을 수정해야 함
|
|
|
|
DSL은 도메인 개념이 언어의 일급 시민이 되므로 두 문제가 모두 해결된다.
|
|
|
|
### 도메인 모델 분리: 체커 게임 사례
|
|
|
|
Ch2의 체커 게임 심판 구현은 DSL 설계의 좋은 교육 사례다:
|
|
|
|
**1단계 — 모놀리식**: 킹(king), 점프(jump) 같은 체커 특화 개념이 코드 전체에 분산됨. 새 규칙을 추가하려면 여러 곳을 수정해야 함.
|
|
|
|
**2단계 — 도메인 모델 분리**:
|
|
- `partial-move(pmove)` 추상화: 이동 경로를 표현하는 도메인 객체
|
|
- **룰 익스큐티브(rule executive)**: 제어 구조를 규칙에서 분리
|
|
- **진화 규칙(evolution rules)**: pmove를 새 pmove들로 변환
|
|
- **집합 규칙(aggregate rules)**: 완료된 pmove 집합에 작용
|
|
- 각 체커 규칙이 단일 프로시저로 표현됨
|
|
|
|
이제 새 규칙(예: "룰 변형" 게임)을 추가하는 것은 새 프로시저를 등록하는 것이다. 기존 규칙 프로시저들은 그대로다.
|
|
|
|
도메인 모델 = 도메인 언어의 프리미티브 + 조합 수단 + 추상화 수단.
|
|
|
|
### 정규표현식: DSL의 나쁜 예
|
|
|
|
> "Regular expressions are a beautiful example of how *not* to build a system."
|
|
|
|
전통 정규표현식의 문제:
|
|
- 컨텍스트 의존성: `^`, `.`, `*`이 위치에 따라 의미가 다름
|
|
- 조합 불가능: `(abc)|(def)` 조각은 독립적으로 재사용할 수 없음
|
|
- 가독성: 복잡한 패턴은 해독이 불가능
|
|
|
|
컴비네이터 기반 대안은 각 부품이 독립적이고, 조합이 안전하며, 의미가 명확하다. 성능이 약간 낮을 수 있지만, 컴파일러로 POSIX BRE로 변환하면 해결된다.
|
|
|
|
### 인터프리터: DSL의 궁극적 형태
|
|
|
|
인터프리터를 만드는 것은 새 언어를 만드는 것이다. Ch5의 인터프리터는 가산적으로 확장 가능하다:
|
|
|
|
- `g:eval`을 제네릭 프로시저로 구현: 새 표현식 타입은 새 핸들러 추가
|
|
- 분석/실행 분리: 새 평가 전략(lazy, amb)은 실행 단계만 수정
|
|
- lazy eval: 매개변수 선언으로 평가 전략 지정 → 선언적 DSL
|
|
|
|
```scheme
|
|
;; 언어 확장: lazy 평가 지원 추가
|
|
(lambda ((lazy x) y) ; x는 필요할 때만 평가
|
|
(if (zero? y) 0 (* x y)))
|
|
```
|
|
|
|
이 확장은 인터프리터의 핸들러를 추가하는 것만으로 이루어진다.
|
|
|
|
### 배선도 언어 (Ch7)
|
|
|
|
전파 모델의 배선도 언어는 또 다른 형태의 DSL이다. 제약(constraint)을 언어의 기본 단위로 삼는 선언적 언어다:
|
|
|
|
```scheme
|
|
;; 곱셈 제약: 세 변수 중 둘을 알면 나머지를 계산
|
|
(c:* a b c)
|
|
|
|
;; 삼각함수 제약
|
|
(c:tan angle ratio)
|
|
```
|
|
|
|
이 언어에서 "프로그램"은 제약들의 네트워크다. 제어 흐름이 없다.
|
|
|
|
## SDF에서의 등장
|
|
|
|
- [[SDF-ch2-dsl]]: 핵심 챕터. 컴비네이터 기반 임베디드 DSL, 정규표현식 DSL, 래퍼, 체커 도메인 모델
|
|
- [[SDF-ch3-generic-procedures]]: 제네릭 산술이 도메인별 확장을 지원하는 DSL의 기반 인프라
|
|
- [[SDF-ch4-pattern-matching]]: 패턴+규칙 시스템이 변환 DSL. 대수 단순화 규칙들이 대수 DSL
|
|
- [[SDF-ch5-evaluation]]: 완전한 인터프리터 구현. lazy eval과 amb를 DSL 확장으로 추가하는 과정
|
|
|
|
## 실천 시 주의점
|
|
|
|
**DSL의 복잡성 비용**: DSL을 만들면 DSL 자체를 배워야 하는 학습 비용이 생긴다. "이 DSL을 쓰는 사람이 나 혼자인가?"를 먼저 물어야 한다. 팀의 크기와 도메인의 복잡성이 DSL 투자를 정당화해야 한다.
|
|
|
|
**임베디드 vs 독립 DSL**: 임베디드 DSL(EDSL)은 호스트 언어의 도구를 모두 쓸 수 있지만, 호스트 언어의 문법 제약을 받는다. 독립 DSL은 문법 자유도가 높지만 파서·인터프리터 구현 비용이 크다. 대부분의 경우 EDSL이 더 실용적이다.
|
|
|
|
**도메인 모델의 안정성**: DSL은 도메인 모델이 안정적일 때 투자할 가치가 있다. 도메인 모델이 자주 변하면 DSL 자체를 수정하는 비용이 DSL이 주는 이점을 상회한다.
|
|
|
|
**에러 메시지 품질**: 사용자가 DSL을 잘못 사용했을 때 의미 있는 에러 메시지를 제공해야 한다. 호스트 언어의 에러가 DSL 사용자에게 노출되면 "내부 구현"이 드러나 추상화가 새는 것이다.
|
|
|
|
## 관련 개념
|
|
|
|
- [[additive-programming]] — DSL은 가산적 확장이 자연스러운 언어 레벨 추상화
|
|
- [[combinators]] — 임베디드 DSL의 핵심 구현 메커니즘
|
|
- [[generic-procedures]] — 제네릭 프로시저로 도메인 연산을 확장 가능하게 구현
|
|
- [[propagation]] — 배선도 언어 자체가 제약 기반 DSL
|