sicp.io
4.1.9 · 내부 정의 끌어내기

평가기는 지역 초기화를 명시적인 형태로 바꿀 수 있다.

프로시저 본문 변환은 내부 이름을 모두 먼저 만들고 대입으로 각 값을 설치한 뒤 남은 본문을 보존해 서로 재귀적인 helper가 하나의 지역 환경을 공유하게 합니다.

생각해 볼 질문

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

  • 프로시저 본문 앞쪽의 내부 정의 알아보기
  • 프로시저 정의 축약형을 명시적인 lambda 값으로 바꾸기
  • 대입 전에 모든 지역 이름을 unassigned 표식으로 만들기
  • 대입 뒤에 정의가 아닌 원래 본문 순서 보존하기
  • 원래 프로그램과 변환한 프로그램을 같은 유한 입력으로 비교하기
  • 화면에 나온 변환과 입력의 일치 관찰하기

scan-out 단계는 프로시저 본문을 데이터로 읽습니다. 앞쪽 define 형식을 모으고 프로시저 정의 축약형을 lambda 식으로 바꾸며, 각 이름을 명시적인 unassigned 표식으로 갖는 let 바인딩을 먼저 만듭니다. 그다음 각 정의의 set!을 놓고 마지막에 원래 남은 본문을 붙입니다. 따라서 어느 클로저가 적용되기 전에 이름들이 한 환경 안에 함께 존재해 서로 재귀적인 helper가 같은 지역 환경을 공유합니다.

두 번째 프로그램은 두 형태를 실제로 실행합니다. classify-original은 내부 정의를 그대로 사용하고 classify-scanned는 변환된 let과 set! 구조를 명시적으로 씁니다. 7과 8에서 같은 결과가 나오며 equal?은 참을 보고합니다. 이 유한 비교는 화면에 나온 변환과 입력의 일치를 확인하고 중간 구조를 직접 드러냅니다.

SICP 코드UTF-8 1,830 / 1,048,576바이트
예제
결과
출력
진단
실행 추적0 / 0 개 이벤트
    실행은 브라우저 안에서 이루어지며 프로그램 결과와 실행 추적을 보여줍니다.
    예상 결과

    변환 프로그램은 even-step과 odd-step을 인용된 *unassigned* 표식에 바인딩한 let 식 하나와 두 set! 형식, 원래 list 본문을 반환합니다. 비교 프로그램은 (#t ((#f #t) (#t #f)) ((#f #t) (#t #f)))를 반환합니다.

    실행 추적에서 볼 점

    변환 실행에서는 인용된 소스 데이터를 읽는 일과 앞쪽 정의 모으기, 바인딩 만들기, 프로시저 정의를 lambda 값으로 바꾸기, 대입 만들기, 남은 본문 붙이기를 구분하세요. 비교 실행에서는 하나의 let 환경과 두 set!, 번갈아 호출되는 클로저를 찾으세요. 일치는 선택한 입력에 대해서만 보고됩니다.

    직접 해보기

    프로그램을 수정하고 결과를 비교해 보세요.

    세 개의 서로 재귀적인 나머지 프로시저로 3의 배수를 알아보는 내부 helper를 추가하세요. 원래 버전과 명시적으로 scan-out한 버전을 모두 쓰고 8과 9의 결과를 비교하세요.

    힌트 보기

    대입 전에 이름 세 개를 모두 만드세요. 각 클로저는 1을 빼고 다음 나머지 프로시저를 호출하며 나머지 0 프로시저만 0에서 참을 반환합니다.

    이 수업 완료하기

    이 장의 총 23개 수업 중 0개 완료0%