(Lispex)sicp.io
제4장 · 점검

문법을 읽고 문맥을 전달하고 저장된 다음 대안을 이어 가세요.

정본 수업 프로그램 열네 개로 표현식 데이터와 환경, 제어, 분석, 파생 문법, 지연된 값, 대안, 패턴 프레임, 규칙 탐색, 논리 한계, 내부 정의 변환, 유한 eval/apply 드라이버, 실패 continuation으로 저장한 선택을 다시 여는 amb 평가기를 연결합니다.

점검 질문

어느 평가기 구성요소가 의미를 고르고 어느 변환이 소스 데이터를 준비하며 어느 환경이 남고 어느 continuation이 다음 비결정적 대안을 제어하는지 설명할 수 있나요?

  • 인용된 표현식 트리를 데이터로 해석하기
  • 환경마다 같은 기호를 다른 값에 연결하기
  • 특수 형식에서 선택한 가지만 평가하기
  • 구조를 한 번 분석하고 실행 계획 재사용하기
  • let을 기존 lambda 적용 규칙으로 바꾸기
  • 명시적인 thunk를 한 번 force하고 메모이즈하기
  • 성공한 모든 유한 대안 유지하기
  • 일관된 패턴 바인딩만 프레임에 넣기
  • 유한 규칙 목표 사이에서 프레임 전달하기
  • 재귀 검색을 frontier와 함께 complete 또는 truncated로 보고하기
  • 실패한 조회와 부정, 선언적 관계와 실행 탐색을 구분하기
  • 내부 이름을 먼저 만들고 대입으로 서로 재귀적인 프로시저 값을 설치하기
  • 인용된 최상위 형식을 eval/apply로 실행하며 하나의 전역 환경에 정의 남기기
  • 성공·실패 continuation을 전달해 require가 앞선 amb 선택으로 돌아가게 하기

앞쪽 프로그램은 프로그램을 데이터로 다루고 환경 조회와 특수 형식과 분석과 파생 문법이 그 데이터의 의미나 형태를 어떻게 바꾸는지 보여 줍니다.

thunk와 대안은 제어 선택을 명시적인 값으로 드러냅니다. 패턴과 유한 질의는 한 목표에서 다음 목표로 일관된 바인딩 프레임을 전달합니다.

재귀 규칙은 frontier와 작업 예산으로 미완료 탐색을 완전한 결과처럼 보이지 않게 하며 논리 한계 수업은 실패한 조회와 증명된 부정을 따로 구분합니다.

내부 정의 수업은 앞쪽 정의를 명시적인 unassigned 바인딩과 대입으로 끌어낸 뒤 유한 입력에서 원래 형태와 변환한 형태를 비교합니다.

유한 평가기 드라이버는 형식 사이에 전역 프레임 변경을 남기고 어휘 클로저 환경을 보존하며 최상위 형식 예산이 배치를 끝냈는지 보고합니다. 그 예산은 한 형식 내부의 재귀 작업을 세지 않습니다.

amb 평가기는 제어 프로토콜 자체를 바꿉니다. 성공할 때마다 다음 선택을 여는 실패 continuation을 함께 전달하고, require의 조건이 거짓이면 그 continuation을 호출하며, all-values는 유한 탐색이 끝나거나 명시적인 해 개수 한도에 닿을 때까지 계속 이어 갑니다.

리스펙스 · SICP 코드SICP에 필요한 Scheme 호환 문법을 리스펙스 SICP 프로필로 실행합니다.
(begin
  (define (evaluate expression)
    (if (number? expression)
        expression
        (let ((operator (car expression))
              (left (cadr expression))
              (right (caddr expression)))
          (cond ((eq? operator '+)
                 (+ (evaluate left) (evaluate right)))
                ((eq? operator '-)
                 (- (evaluate left) (evaluate right)))
                ((eq? operator '*)
                 (* (evaluate left) (evaluate right)))))))
  (evaluate '(+ (* 3 4) (- 10 2))))
리스펙스 학습용 런타임리스펙스 SICP 프로필 1.0.0
리스펙스 SICP 런타임 불러오는 중
리스펙스 · SICP 코드UTF-8 519 / 1,048,576바이트
예제
결과
출력
진단
보이는 실행 흐름0 / 0 개의 실행 이벤트
    이 브라우저 결과는 리스펙스 바우치나 권한이 아닙니다.wasm —
    예상 관찰

    각 프로그램은 대응하는 제4장 수업의 첫 예상 관찰을 반환합니다. 유한 드라이버는 (complete ((defined square) (defined make-adder) (defined add-five) (defined base) 49 12 (assigned base) 81 6) 0)을 반환하고 amb 평가기의 제약 쌍 탐색은 (complete ((1 4) (2 3)))을 반환합니다.

    실행 흐름에서 볼 점

    표현식 순회, 환경 조회, 분기, 분석, let 변환, thunk 상태, 프레임 확장, 목표 전달, frontier 확장, 실패한 사실 스캔, 정의 모으기, 전역 프레임 변경, 복합 프로시저 적용, 클로저 환경 캡처, 최상위 예산 감소, amb 선택 저장, require 실패, 뒤쪽 인자 선택을 이어 가는 continuation을 찾아보세요. 이 제한된 실행은 무한 탐색의 공정성이나 완전성을 증명하지 않습니다.

    답을 보기 전에 설명하기

    평가기와 변환과 규칙과 continuation을 생각하는 질문 열네 개

    표현식 데이터를 값으로 바꾸려면 평가기는 무엇을 해야 할까요?

    Numbers evaluate directly. A compound expression asks evaluate to interpret both nested operands before combining their values. The evaluator follows the expression tree one node at a time.

    같은 표현식이 다른 환경에서 다른 값을 만드는 이유는 무엇일까요?

    evaluate does not attach one permanent meaning to x or y. It receives an environment with the expression, so the same expression tree can be reused with different bindings.

    평가기가 if의 두 가지를 모두 평가하면 무엇이 잘못될까요?

    In the first example the alternative divides by zero. The program still returns 60 because the true predicate selects the addition branch and the invalid alternative remains expression data.

    환경이 오기 전에 어떤 일을 미리 끝낼 수 있을까요?

    The resulting plan accepts an environment. Running it only looks up variables, runs the stored operand plans, and applies the already selected operator. One analyzed plan can therefore serve many environments.

    let을 lambda 적용으로 바꿀 때 무엇이 그대로 남아야 할까요?

    The evaluator does not need a second implementation of local binding. Its let case rewrites the expression and sends the result back through the ordinary lambda and application cases in the same environment.

    call-by-need를 평가기 안에서 보이게 하는 표현 변화는 무엇일까요?

    force-it inspects the tag. On the first demand it calls the stored computation, changes the tag to evaluated-thunk, discards the computation, and stores the value. Later demands select the cached slot and perform no computation again. This exposes the representation change that a lazy evaluator normally hides behind argument handling.

    성공 하나 뒤에도 남은 대안을 유지하면 평가가 어떻게 달라질까요?

    The second program makes two choice positions explicit. scan-y tests every y for one x, and scan-x repeats that work for every x. Returning all pairs whose squared components sum to 25 exposes a finite nondeterministic search as ordinary list-producing control.

    매처는 두 데이터 구조를 걸으며 부분 지식을 어떻게 전달할까요?

    A later occurrence looks up the existing binding before extending anything. Equal data preserves the frame; conflicting data returns failed, which every remaining recursive step propagates. This is one-way matching with variables in the pattern, not full bidirectional unification or database search.

    규칙은 다음 목표가 필요로 하는 중간 바인딩을 어떻게 보존할까요?

    The second program binds grand from the rule head, then solve-goals processes the two parent goals in order. The first goal produces middle values ben and dia. Each frame becomes input to the second goal, which finds cy and eli. This deliberately narrow evaluator supports parent goals in one finite rule body. It does not implement variable renaming, negation, recursive rules, duplicate removal, or general unification.

    데이터에 순환이 있어도 재귀 규칙 확장을 정직하게 끝내려면 무엇이 필요할까요?

    The second program uses a three-person cycle. Expanding ada reaches ben, ben reaches cy, and cy reaches ada again. The evaluator spends exactly one work unit per removed frontier item and returns truncated with the remaining frontier when the budget reaches zero. It does not silently present the repeated prefix as the complete ancestor relation. This narrow breadth-first model does not implement general unification, variable renaming, duplicate removal, negation, fairness, or a complete logic-programming engine.

    어떤 결론은 논리 관계에서 나오고 어떤 결론은 특정 데이터베이스와 탐색 절차에서 나올까요?

    두 번째 프로그램은 married 관계에 대칭 탐색 규칙을 붙입니다. 직접 사실이 없으면 인자를 바꾸어 다시 찾습니다. 이 규칙은 반대 방향 사실이 있는 (married mickey minnie)를 한 번 뒤집어 증명합니다. 관련 없는 두 사람은 반복 탐지를 하거나 작업 예산을 쓰지 않으면 같은 두 질의를 끝없이 왕복합니다. 논리 관계가 대칭이어도 규칙의 방향과 제어가 실제 탐색의 동작을 결정합니다.

    평가기는 왜 프로시저 값을 하나라도 설치하기 전에 내부 바인딩을 모두 먼저 만들어야 할까요?

    두 번째 프로그램은 두 형태를 실제로 실행합니다. classify-original은 내부 정의를 그대로 사용하고 classify-scanned는 변환된 let과 set! 구조를 명시적으로 씁니다. 7과 8에서 같은 결과가 나오며 equal?은 참을 보고합니다. 이 유한 비교는 이번 변환과 입력을 확인할 뿐 모든 Scheme 프로그램의 의미 동등성을 증명하거나 숨은 리스펙스 컴파일 단계를 드러내거나 모든 구현의 중간 표현을 규정하지 않습니다.

    평가기 프로시저 모음을 사용자 형식의 수열을 실행하는 하나의 프로그램으로 만드는 것은 무엇일까요?

    run-program이 드라이버입니다. 인용된 최상위 형식과 하나의 전역 환경과 형식 예산을 받습니다. 끝난 형식마다 transcript 값 하나를 남기며 정의와 대입은 뒤 형식에서도 보입니다. 전체 실행은 square와 make-adder와 add-five와 base를 정의합니다. add-five는 전역 base가 바뀐 뒤에도 지역 x 값 5를 유지합니다. 두 번째 실행은 다섯 형식 뒤에 멈추고 형식 네 개가 남았다고 보고합니다. 이 형식 예산은 한 형식 안의 재귀나 작업량을 제한하지 않으며 그 아래 실행 경계는 패키지된 브라우저 런타임이 담당합니다.

    평가기는 실패를 종료 오류가 아니라 이전 선택점의 다음 대안을 다시 시작하라는 요청으로 어떻게 바꿀까요?

    require는 같은 continuation 체계 안에서 술어를 평가합니다. 참이면 ok로 성공하고 거짓이면 다음 술어 대안을 호출하며 결국 가장 가까운 amb 선택점으로 돌아갑니다. all-values는 성공마다 받은 다음 대안을 계속 호출합니다. 첫 실행은 유한 탐색을 모두 소진해 complete를 보고하고 두 번째는 해 네 개 뒤에 일부러 멈춰 truncated를 보고합니다. 이 수업은 되돌릴 수 있는 set!과 permanent-set!, 무작위 선택 순서, 중복 제거, 무한 탐색 공간의 공정성을 구현하지 않습니다.