타입 태그가 표현에 맞는 연산을 고른다.
범용 인터페이스는 연산 이름과 데이터 타입을 하나의 키로 묶어 호출하는 곳마다 분기하지 않고 표에서 맞는 프로시저를 찾을 수 있습니다.
생각해 볼 질문
연산 표는 서로 다른 표현에서도 하나의 인터페이스를 어떻게 유지할까요?
- 표현 내용에 명시적인 타입 태그 붙이기
- 연산과 타입 순서쌍을 디스패치 키로 사용하기
- 직교형과 극형의 magnitude 공식을 따로 두기
- 두 표현에 같은 범용 magnitude 인터페이스 호출하기
표의 각 항목은 (magnitude type) 키와 그 타입의 내용만 이해하는 프로시저를 짝지어 둡니다. 직교형 프로시저는 x²+y²의 제곱근을 계산하고 극형 프로시저는 저장된 반지름을 읽습니다.
apply-generic은 get이 맞는 프로시저를 고른 뒤에야 태그를 떼고 내용만 넘깁니다. 사용하는 코드는 magnitude와 태그가 붙은 데이터만 주면 되며 어떤 표현인지 직접 묻지 않습니다. 새 표현을 더할 때 바뀌는 곳은 범용 인터페이스가 아니라 표입니다.
(begin
(define operation-table
(list
(cons (list 'magnitude 'rectangular)
(lambda (contents)
(sqrt (+ (* (car contents) (car contents))
(* (cadr contents) (cadr contents))))))
(cons (list 'magnitude 'polar)
(lambda (contents) (car contents)))))
(define (get operation type table)
(cond ((null? table) #f)
((and (eq? operation (car (car (car table))))
(eq? type (cadr (car (car table)))))
(cdr (car table)))
(else (get operation type (cdr table)))))
(define (attach-tag type contents) (cons type contents))
(define (apply-generic operation object)
(let ((procedure (get operation (car object) operation-table)))
(procedure (cdr object))))
(list
(apply-generic 'magnitude
(attach-tag 'rectangular (list 3.0 4.0)))
(apply-generic 'magnitude
(attach-tag 'polar (list 5.0 0.0)))))리스펙스 학습용 런타임리스펙스 SICP 프로필 1.0.0
리스펙스 SICP 런타임 불러오는 중
리스펙스 · SICP 코드UTF-8 969 / 1,048,576바이트
예제
결과—
- 출력
- —
- 값
- —
- 진단
- —
보이는 실행 흐름0 / 0 개의 실행 이벤트
첫 프로그램은 (5.0 5.0)을 반환합니다. 두 번째 프로그램은 (13.0 13.0)을 반환합니다.
apply-generic이 선택한 프로시저에 내용만 넘기기 전에 get이 연산과 타입 키를 비교하는 과정을 따라가세요. 직교형 실행은 sqrt에 닿고 극형 실행은 첫 내용 필드를 반환합니다. 제한된 실행 흐름은 선택한 이번 실행만 설명하며 리스펙스 바우치나 권한이 아닙니다.
힌트를 보기 전에 프로그램을 바꿔 보세요.
linear라는 1차원 표현의 magnitude 항목을 추가한 뒤 기존 apply-generic을 바꾸지 않고 저장 길이 9.0을 실행하세요.
힌트 하나 보기
새 키는 (magnitude linear)입니다. 프로시저는 내용의 첫 필드를 반환하면 됩니다.