(Lispex)sicp.io
3.12 · 가변 테이블 표현하기

테이블은 레코드를 바꾸고 lookup은 표현을 비공개로 남긴다.

연관 리스트를 lookup과 insert! 뒤에 숨기면 기존 레코드를 제자리에서 바꾸고, 없는 레코드를 테이블에 연결하고, 두 번째 키를 하위 테이블로 표현하면서도 클라이언트의 사용 방법을 유지할 수 있습니다.

생각해 볼 질문

테이블에서 한 레코드를 갱신하거나 새로운 중첩 키 경로를 만들 때 어떤 연결을 바꿔야 할까요?

  • 테이블 헤더 뒤에서 assoc으로 가변 레코드 찾기
  • set-cdr!로 기존 레코드 갱신하기
  • 테이블 꼬리를 바꾸어 새 레코드 삽입하기
  • 두 키 테이블을 레코드를 담은 하위 테이블로 표현하기
  • 조회 실패와 저장된 값 구분하기

한 키 테이블은 첫 항목이 비공개 헤더인 가변 리스트입니다. lookup은 헤더 뒤의 레코드만 검색합니다. insert!는 키가 있으면 기존 키-값 순서쌍의 cdr을 바꾸고, 키가 없으면 테이블 헤더 순서쌍의 cdr을 바꾸어 새 레코드를 연관 리스트에 연결합니다. 클라이언트 코드는 삽입 순서나 순서쌍 배치에 의존하지 않습니다.

두 키 테이블은 첫 번째 키 레코드의 cdr에 또 다른 연관 리스트를 저장합니다. 새로운 두 번째 키는 그 하위 테이블을 바꾸고, 새로운 첫 번째 키는 완전한 하위 테이블을 바깥 테이블에 연결합니다. arithmetic 값을 10에서 11로 바꾸는 일은 중복 레코드를 만들지 않고 가장 안쪽 기존 레코드를 갱신합니다. 이 예제는 #f를 조회 실패로 사용하므로 #f 자체를 저장하려면 더 풍부한 조회 규약이 필요합니다.

리스펙스 · SICP 코드SICP에 필요한 Scheme 호환 문법을 리스펙스 SICP 프로필로 실행합니다.
(begin
  (define (make-table) (list '*table*))
  (define (lookup key table)
    (let ((record (assoc key (cdr table))))
      (if record (cdr record) #f)))
  (define (insert! key value table)
    (let ((record (assoc key (cdr table))))
      (if record
          (set-cdr! record value)
          (set-cdr! table
                    (cons (cons key value)
                          (cdr table)))))
    'ok)
  (define table (make-table))
  (insert! 'alpha 4 table)
  (insert! 'beta 5 table)
  (insert! 'alpha 9 table)
  (list (lookup 'alpha table)
        (lookup 'beta table)
        (lookup 'gamma table)
        table))
리스펙스 학습용 런타임리스펙스 SICP 프로필 1.0.0
리스펙스 SICP 런타임 불러오는 중
리스펙스 · SICP 코드UTF-8 621 / 1,048,576바이트
예제
결과
출력
진단
보이는 실행 흐름0 / 0 개의 실행 이벤트
    이 브라우저 결과는 리스펙스 바우치나 권한이 아닙니다.wasm —
    예상 관찰

    첫 프로그램은 (9 5 #f (*table* (beta . 5) (alpha . 9)))를 반환합니다. 두 번째 프로그램은 (11 20 30 #f (*table* (language (scheme . 30)) (math (algebra . 20) (arithmetic . 11))))을 반환합니다.

    실행 흐름에서 볼 점

    alpha를 찾는 assoc 순회와 끝까지 가는 gamma 순회를 비교하세요. 기존 레코드의 set-cdr!과 새 레코드를 연결하는 테이블 또는 하위 테이블 헤더의 set-cdr!을 구분하세요. 중첩 실행에서는 바깥 키를 먼저 찾은 뒤 안쪽 키를 찾고 arithmetic 갱신이 기존 순서쌍 하나를 바꾸는지 확인하세요.

    직접 해보기

    힌트를 보기 전에 프로그램을 바꿔 보세요.

    math 아래에 physics를 추가하고 scheme을 31로 갱신한 뒤 두 번째 language 레코드를 넣으세요. 실행 전에 바깥과 안쪽 레코드 순서를 예상하고 어떤 연산이 레코드를 바꾸며 어떤 연산이 테이블 꼬리를 바꾸는지 설명하세요.

    힌트 하나 보기

    이미 있는 키는 해당 레코드의 cdr을 바꿉니다. 없는 키는 새 순서쌍을 만들고 관련 연관 리스트의 앞에 연결합니다.