Files
softwaredesign/wiki/sources/SDF-ch3-generic-procedures.md
minsung ea46da91db feat: SDF wiki 컴파일 — 챕터별 한국어 소스 페이지 8개
Software Design for Flexibility (Hanson & Sussman 2021) 전문을
wiki/sources/ 아래 챕터별 한국어 wiki 페이지로 컴파일

- SDF-overview: 전체 개요, 챕터 관계도, 공통 테마
- SDF-ch1: 가산적 프로그래밍 철학, 퇴화성, 유연성 비용
- SDF-ch2: 컴비네이터, DSL, 래퍼, 도메인 모델
- SDF-ch3: 제네릭 프로시저, 자동 미분, 트라이 디스패치
- SDF-ch4: 패턴 매칭, 항 재작성, 단일화, 타입 추론
- SDF-ch5: eval/apply, lazy eval, amb, call/cc
- SDF-ch6: 레이어드 데이텀/프로시저, 단위 산술, 의존성 추적
- SDF-ch7: 전파 모델, 부분 정보 결합, 의존성 지향 백트래킹

wiki/index.md Sources 섹션 등록, wiki/log.md 기록

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 14:42:02 +09:00

6.3 KiB

title, tags, source, chapter, updated
title tags source chapter updated
Ch3: Variations on an Arithmetic Theme
source
SDF
Software Design for Flexibility, Hanson & Sussman (2021) 3 2026-04-30

Ch3: Variations on an Arithmetic Theme

핵심 아이디어

**술어-디스패치 제네릭 프로시저(predicate-dispatched generic procedures)**를 중심으로, 기존 프로그램의 동작을 확장하는 강력하지만 위험한 기법을 다룬다. 산술 연산의 의미를 수치에서 기호, 함수, 미분 객체로 확장하는 과정을 통해 제네릭 시스템의 설계 원칙을 보여준다.

주요 개념

3.1 산술 패키지 컴비네이터

산술 패키지(arithmetic package): 연산자 이름에서 구현으로의 매핑. install-arithmetic!으로 사용자 환경에 설치.

적용 가능성 명세(applicability specification): 술어 리스트의 리스트. 인수들이 케이스 중 하나를 만족하면 해당 핸들러 적용.

;; 수치 산술: (number? number?) 케이스만 적용
;; 기호 산술: (number? symbolic?), (symbolic? number?),
;;           (symbolic? symbolic?) 케이스에 적용

(define combined-arithmetic
  (extend-arithmetic symbolic-extender numeric-arithmetic))

add-arithmetics 컴비네이터로 산술들을 결합. 그러나 컴비네이터 방식은 한계가 있다:

  • 부품의 형태를 미리 결정해야 함
  • 계층화된 구조(예: 함수 산술)를 나중에 확장하기 어려움
  • 자기 참조 구조 불가

3.2 확장 가능한 제네릭 프로시저

컴비네이터의 한계를 극복하기 위해 동적으로 확장 가능한 제네릭 프로시저 도입.

;; 생성
(define plus (simple-generic-procedure 'plus 2 #f))

;; 핸들러 추가
(define-generic-procedure-handler plus
  (all-args 2 number?)
  (lambda (a b) (+ a b)))

(define-generic-procedure-handler plus
  (any-arg 2 symbolic? number?)
  (lambda (a b) (list '+ a b)))

구현 메커니즘:

  1. generic-procedure-constructor: 디스패치 전략을 인자로 받아 제네릭 프로시저 생성기 반환
  2. dispatch-store: 핸들러 저장/검색 전략 캡슐화
  3. 메타데이터 테이블: 제네릭 프로시저에 "스티키 노트"로 규칙 목록 첨부

제네릭 산술의 폐쇄성(closure): 모든 확장을 제네릭 산술 자체를 기반으로 만들면 자기 참조 구조가 가능하다.

(let ((g (make-generic-arithmetic make-simple-dispatch-store)))
  (add-to-generic-arithmetic! g numeric-arithmetic)
  (extend-generic-arithmetic! g symbolic-extender)
  (extend-generic-arithmetic! g function-extender)
  (install-arithmetic! g))

주의: 핸들러 추가 순서에 의존성이 생길 수 있다. 적용 가능성이 겹치는 규칙들의 순서에 따라 결과가 달라짐.

3.3 자동 미분 (Automatic Differentiation)

제네릭 프로시저의 탁월한 응용 예시. 미분 객체(differential object) [x, δx]를 새 데이터 타입으로 도입:

[x, \delta x] \xrightarrow{f} [f(x), Df(x)\delta x]

각 산술 연산에 미분 객체 처리 핸들러를 추가하기만 하면, 함수의 합성을 통해 연쇄 법칙이 자동으로 적용된다.

(define (derivative f)
  (define (the-derivative x)
    (let* ((dx (make-new-dx))
           (value (f (d:+ x (make-infinitesimal dx)))))
      (extract-dx-part value dx)))
  the-derivative)

;; sqrt의 미분 핸들러
(define diff:sqrt
  (diff:unary-proc sqrt (lambda (x) (/ 1 (* 2 (sqrt x))))))

고차 함수(함수를 반환하는 함수)에서의 미분은 기술적 복잡성이 있다: dx 태그 충돌 문제를 replace-dx 메커니즘으로 해결.

3.4 효율적인 디스패치

단순 선형 스캔의 문제: 많은 규칙에서 동일한 술어를 반복 호출.

트라이(Trie) 기반 디스패치:

  • 인수 시퀀스를 트라이로 인덱싱
  • 첫 번째 인수의 타입으로 후보 규칙 집합을 좁힘
  • 중복 술어 평가 제거

캐싱:

  • 인수의 구현 타입 태그를 키로 사용
  • 이전 디스패치 결과를 해시 테이블에 캐시
  • cache-wrapped-dispatch-store로 임의의 디스패치 전략에 캐싱 추가

3.5 사용자 정의 타입

추상 술어(abstract predicate): 비용이 높은 술어 평가를 메모이즈. 객체에 태그를 붙여 이후 디스패치에서 비싼 술어 재평가 불필요.

(define prime-number?
  (simple-abstract-predicate 'prime-number slow-prime?))

(set-predicate<=! prime-number? exact-integer?)
;; 이후 exact-integer? 도 prime-number 객체를 인식

서브타입 관계 선언: set-predicate<=!로 부분집합 관계 명시. 가장 특수적인 핸들러가 선택됨.

3.5.4 어드벤처 게임

제네릭 프로시저와 사용자 정의 타입의 실용적 응용 예시.

;; 이동 행동이 4개 인수 타입의 조합에 따라 달라짐
(define generic-move!
  (most-specific-generic-procedure 'generic-move! 4 #f))

(define-generic-procedure-handler generic-move!
  (match-args mobile-thing? place? bag? person?) ...)
(define-generic-procedure-handler generic-move!
  (match-args mobile-thing? bag? place? person?) ...)
(define-generic-procedure-handler generic-move!
  (match-args person? place? place? person?) ...)

단일 디스패치 OOP와 달리, 모든 인수 타입의 조합에 따라 행동이 결정되므로 더 자연스러운 분해가 가능하다.

핵심 인용

"Systems built by combinators, as in section 3.1, result in beautiful diamond-like systems. This is sometimes the right idea... but it is very hard to add to a diamond. If a system is built as a ball of mud, it is easy to add more mud."

"Construction of a system on a substrate of extensible generic procedures is a powerful idea... a user may extend them to support arithmetic on quaternions, vectors, matrices, integers modulo a prime, functions, tensors, differential forms..."

"It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures." (Alan Perlis)

관련 개념