2011-08-24 1 views
8

SICP 4.1 (http://mitpress.mit.edu/sicp/full-text/book/book-ZH-26.html)에 설명 된 프로그램을 실행하려고합니다. 하지만이 책에서 알 수 있듯이 함수 apply을 다시 정의하는 데 약간의 어려움이 있습니다. 코드는 다음DrRacket에서 Metacircular Evaluator를 실행하는 방법

#lang planet neil/sicp 

;; ----------------------------------------------------------------------------- 
;; 4.1.1 The Core of the Evaluator 
;; ----------------------------------------------------------------------------- 

;; Eval 
(define apply-in-underlying-scheme apply) 
(define (eval exp env) 
    (display 'eval) 
    (newline) 
    (display exp) 
    (newline) 
    (cond ((self-evaluating? exp) exp) 
     ((variable? exp) (let ((res (lookup-variable-value exp env))) 
          (display (list 'lookup exp)) 
          (newline) 
          (display res) 
          (newline) 
          res)) 
     ((quoted? exp) (text-of-quotation exp)) 
     ((assignment? exp) (eval-assignment exp env)) 
     ((definition? exp) (eval-definition exp env)) 
     ((if? exp) (eval-if exp env)) 
     ((lambda? exp) 
     (make-procedure (lambda-parameters exp) 
         (lambda-body exp) 
         env)) 
     ((begin? exp) 
     (eval-sequence (begin-actions exp) env)) 
     ((cond? exp) (eval (cond->if exp) env)) 
     ((application? exp) 
     (apply (eval (operator exp) env) 
       (list-of-values (operands exp) env))) 
     (else 
     (error "Unknown expression" exp)))) 

;; Apply 

(define (apply procedure arguments) 
    (display 'apply) 
    (newline) 
    (display procedure) 
    (newline) 
    (cond ((primitive-procedure? procedure) 
     (apply-primitive-procedure procedure arguments)) 
     ((compound-procedure? procedure) 
     (eval-sequence 
      (procedure-body procedure) 
      (extend-environment 
      (procedure-parameters procedure) 
      arguments 
      (procedure-environment procedure)))) 
     (else 
      (error 
      "Unknown procedure type -- " procedure)))) 



;; Application 

(define (application? exp) (pair? exp)) 
(define (operator exp) (car exp)) 
(define (operands exp) (cdr exp)) 

;; Procedure arguments 

(define (list-of-values exps env) 
    (if (no-operands? exps) 
     '() 
     (cons (eval (first-operand exps) env) 
      (list-of-values (rest-operands exps) env)))) 

(define (no-operands? ops) (null? ops)) 
(define (first-operand ops) (car ops)) 
(define (rest-operands ops) (cdr ops)) 

;; Conditionals 

(define (eval-if exp env) 
    (if (true? (eval (if-predicate exp) env)) 
     (eval (if-consequent exp) env) 
     (eval (if-alternative exp) env))) 

;; Sequences 

(define (eval-sequence exps env) 
    (cond ((last-exp? exps) (eval (first-exp exps) env)) 
     (else (eval (first-exp exps) env) 
       (eval-sequence (rest-exps exps) env)))) 

;; Assignments and definitions 

(define (eval-assignment exp env) 
    (set-variable-value! (assignment-variable exp) 
         (eval (assignment-value exp) env) 
         env) 
    'ok) 

(define (eval-definition exp env) 
    (define-variable! (definition-variable exp) 
        (eval (definition-value exp) env) 
        env) 
    'ok) 

;; Representing Expressions 

;; self evaluating := items, numbers 

(define (self-evaluating? exp) 
    (cond ((number? exp) true) 
     ((string? exp) true) 
     (else false))) 

;; variables = symbol 

(define (variable? exp) (symbol? exp)) 

;; (quote <text-of-quotation>) 

(define (quoted? exp) (tagged-list? exp 'quote)) 

(define (text-of-quotation exp) (cadr exp)) 

(define (tagged-list? exp tag) 
    (if (pair? exp) 
     (eq? (car exp) tag) 
     false)) 

;; (set! <var> <value>) 

(define (assignment? exp) 
    (tagged-list? exp 'set!)) 

(define (assignment-variable exp) (cadr exp)) 
(define (assignment-value exp) (caddr exp)) 

;; (define <var> <value>) 
;; or 
;; (define <var> 
;; (lambda (<parameter-1> ... <parameter-n>) 
;;  <body>)) 
;; or 
;; (define (<var> <parameter-1> ... <parameter-n>) 
;; <body>) 

(define (definition? exp) 
    (tagged-list? exp 'define)) 

(define (definition-variable exp) 
    (if (symbol? (cadr exp)) 
     (cadr exp) 
     (caadr exp))) 

(define (definition-value exp) 
    (if (symbol? (cadr exp)) 
     (caddr exp) 
     (make-lambda (cdadr exp) ;; formal params 
        (cddr exp)))) ;; body 

;; lambda 

(define (lambda? exp) (tagged-list? exp 'lambda)) 

(define (lambda-parameters exp) (cadr exp)) 
(define (lambda-body exp) (cddr exp)) 

;; constructor for lambda expression 

(define (make-lambda parameters body) 
    (cons 'lambda (cons parameters body))) 

;; if 

(define (if? exp) (tagged-list? exp 'if)) 
(define (if-predicate exp) (cadr exp)) 
(define (if-consequent exp) (caddr exp)) 
(define (if-alternative exp) 
    (if (not (null? (caddr exp))) 
     (cadddr exp) 
     'false)) 

;; constructor to transform cond expressions to if expressions 

(define (make-if predicate consequent alternative) 
    (list 'if predicate consequent alternative)) 

;; begin 

(define (begin? exp) (tagged-list? exp 'begin)) 
(define (begin-actions exp) (cdr exp)) 
(define (last-exp? seq) (null? (cdr seq))) 
(define (first-exp seq) (car seq)) 
(define (rest-exps seq) (cdr seq)) 

;; sequence->exp 

(define (sequence->exp seq) 
    (cond ((null? seq) seq) 
     ((last-exp? seq) (first-exp seq)) 
     (else (make-begin seq)))) 

(define (make-begin seq) (cons 'begin seq)) 

;; derived expressions 

(define (cond? exp) (tagged-list? exp 'cond)) 

(define (cond-clauses exp) (cdr exp)) 

(define (cond-else-clause? clause) 
    (eq? (cond-predicate clause) 'else)) 

(define (cond-predicate clause) (car clause)) 
(define (cond-actions clause) (cdr clause)) 

(define (cond->if exp) 
    (expand-clauses (cond-clauses exp))) 

(define (expand-clauses clauses) 
    (if (null? clauses) 
     'false 
     (let ((first (car clauses)) 
      (rest (cdr clauses))) 
     (if (cond-else-clause? first) 
      (if (null? rest) 
       (sequence->exp (cond-actions first)) 
       (error "ELSE clause isn't last -- COND->IF" 
         clauses)) 
      (make-if (cond-predicate first) 
        (sequence->exp (cond-actions first)) 
        (expand-clauses rest)))))) 

;; Representing procedures 

;; (apply-primitive-procedure <proc> <args>) 
;; (primitive-procedure? <proc>) 

(define (make-procedure parameters body env) 
    (list 'procedure parameters body env)) 

(define (compound-procedure? p) 
    (tagged-list? p 'procedure)) 

(define (procedure-parameters p) (cadr p)) 
(define (procedure-body p) (caddr p)) 
(define (procedure-environment p) (cadddr p)) 

;; Operations on Environments 

;; env is nothing but a list of frames. 
(define the-empty-environment '()) 

(define (enclosing-environment env) (cdr env)) 
(define (first-frame env) (car env)) 

;; each frames contains variables and values 
(define (make-frame variables values) 
    (cons variables values)) 

(define (frame-variables frame) (car frame)) 
(define (frame-values frame) (cdr frame)) 

(define (add-binding-to-frame! var val frame) 
    (set-car! frame (cons var (car frame))) 
    (set-cdr! frame (cons val (cdr frame)))) 

;; (extend-environment <variables> <values> <base-env>) 

(define (extend-environment vars vals base-env) 
    (if (= (length vars) (length vals)) 
     (cons (make-frame vars vals) base-env) 
     (if (< (length vars) (length vals)) 
      (error "Too many arguments supplied" vars vals) 
      (error "Too few arguments supplied" vars vals)))) 

;; (lookup-variable-value <var> <env>) 

(define (lookup-variable-value var env) 
    (define (env-loop env) 
    (define (scan vars vals) 
     (cond ((null? vars) 
      (env-loop (enclosing-environment env))) 
      ((eq? var (car vars)) 
      (car vals)) 
      (else (scan (cdr vars) (cdr vals))))) 
    (if (eq? env the-empty-environment) 
     (error "Unbound variable" var) 
     (let ((frame (first-frame env))) 
      (scan (frame-variables frame) 
       (frame-values frame))))) 
    (env-loop env)) 

;; (set-variable-value! <var> <value> <env>) 

(define (set-variable-value! var val env) 
    (define (env-loop env) 
    (define (scan vars vals) 
     (cond ((null? vars) 
      (env-loop (enclosing-environment env))) 
      ((eq? var (car vars)) 
      (set-car! vals val)) 
      (else (scan (cdr vars) (cdr vals))))) 
    (if (eq? env the-empty-environment) 
     (error "Unbound variable -- SET!" var) 
     (let ((frame (first-frame env))) 
      (scan (frame-variables frame) 
       (frame-values frame))))) 
    (env-loop env)) 

;; (define-variable! <var> <value> <env>) 

(define (define-variable! var val env) 
    (let ((frame (first-frame env))) 
    (define (scan vars vals) 
     (cond ((null? vars) 
      (add-binding-to-frame! var val frame)) 
      ((eq? var (car vars)) 
      (set-car! vals val)) 
      (else (scan (cdr vars) (cdr vals))))) 
    (scan (frame-variables frame) 
      (frame-values frame)))) 

(define (true? x) 
    (not (eq? x false))) 

(define (false? x) 
    (eq? x false)) 

;; ----------------------------------------------------------------------------- 
;; 4.1.4 - Running the Evaluator as a Program 
;; ----------------------------------------------------------------------------- 

(define (primitive-procedure? proc) 
    (tagged-list? proc 'primitive)) 

(define (primitive-implementation proc) (cadr proc)) 

(define primitive-procedures 
    (list (list 'car car) 
     (list 'cdr cdr) 
     (list 'cons cons) 
     (list 'null? null?) 
     )) 

(define (primitive-procedure-names) 
    (map car 
     primitive-procedures)) 

(define (primitive-procedure-objects) 
    (map (lambda (proc) (list 'primitive (cadr proc))) 
     primitive-procedures)) 

(define (apply-primitive-procedure proc args) 
    (apply-in-underlying-scheme 
    (primitive-implementation proc) args)) 

(define (setup-environment) 
    (let ((initial-env 
     (extend-environment (primitive-procedure-names) 
          (primitive-procedure-objects) 
          the-empty-environment))) 
    (define-variable! 'true true initial-env) 
    (define-variable! 'false false initial-env) 
    initial-env)) 

;; for scheme, uncomment for lisp 
;;(define true #t) 
;;(define false #f) 

(define input-prompt " mscheme > ") 
(define output-prompt " .. ") 

(define (driver-loop) 
    (prompt-for-input input-prompt) 
    (let ((input (read))) 
    (let ((output (eval input the-global-environment))) 
     (announce-output output-prompt) 
     (user-print output))) 
    (driver-loop)) 

(define (prompt-for-input string) 
    (newline) (newline) (display string) (newline)) 

(define (announce-output string) 
    (newline) (display string) (newline)) 

(define (user-print object) 
    (if (compound-procedure? object) 
     (display (list 'compound-procedure 
        (procedure-parameters object) 
        (procedure-body object) 
        '<procedure-env>)) 
     (display object))) 

;; start repl 
(define the-global-environment (setup-environment)) 
(driver-loop) 

를 문제 내가 같이 적용 내장 계획을 저장하려고 시작이며, "에 - 기본 - 계획 - 적용됩니다." 아래에 작성된 "apply"라는 또 다른 함수가 있기 때문에 "정의 이전에 식별자에 대한 참조 : 적용"이라는 오류 메시지가 나타납니다. 어떻게하면 여기에 오류가 발생하지 않고 내장 된 "적용"을 참조 할 수 있습니까?

답변

7

SICP가 apply을 호출하는 기능의 이름을 metacircular-apply 또는 그와 비슷한 것으로 바꿀 수 있습니다. 미학 이외에는 apply이라고 부를 필요가 없습니다.

1

제가 적용 -에 - 기본 - 제도 적용의 이름을 변경 다음 헤더를 사용 : 당신은 라켓 언어의 정의를 다시 정의 할 수는 없지만

#!r6rs 
(import (except (rnrs base) apply) 
     (rnrs io simple) 
     (rename (rnrs base) (apply apply-in-underlying-scheme)) 
     (rnrs mutable-pairs)) 
1

#lang racket 또는 이와 유사한, 당신이 필요로 사용할 수 있습니다 라켓 모듈 시스템의 특징입니다.

(require (only-in racket [apply apply-in-underlying-scheme])) 

여기 only-in 우리가 지정한 경우에만 바인딩이 여기에 내장 된 모듈 racket에서 apply 인,로드된다는 것을 의미합니다.

우리는 또한 rename-in 대신 only-in을 사용할 수 있지만, racket 모듈이 항상 라켓 언어의 일부로로드되어 있기 때문에, 우리는 그것을 모두를 다시 가져올 필요가 있고, 따라서 단지 only-in를 사용하지 마십시오.