2011-08-24 14 views
8

Tôi đang cố gắng chạy chương trình được mô tả trong SICP 4.1 (http://mitpress.mit.edu/sicp/full-text/book/book-ZH-26.html) nhưng đã gặp phải một số khó khăn trong việc xác định lại chức năng apply vì cuốn sách đề nghị bạn nên làm. Mã này là như sau:Cách chạy Trình Đánh giá Metacircular trong DrRacket

#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) 

Vấn đề là sự khởi đầu, nơi tôi đang cố gắng để lưu các chương trình BUILTIN áp dụng là "apply-in-cơ bản đề án." Vì có một hàm khác có tên là "áp dụng" được viết dưới đây, tôi nhận được lỗi "tham chiếu đến một định danh trước khi định nghĩa của nó: áp dụng." Làm thế nào tôi có thể tham khảo nội trang "áp dụng" mà không gây ra lỗi ở đây?

Trả lời

7

Bạn chỉ có thể đổi tên hàm SICP gọi apply thành metacircular-apply hoặc tương tự như vậy. Không cần phải gọi nó là apply ngoài tính thẩm mỹ.

1

tôi sử dụng tiêu đề sau đây, mà đổi tên áp dụng để áp dụng-trong-cơ bản đề án:

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

Trong khi bạn không thể xác định lại một định nghĩa bằng ngôn ngữ vợt #lang racket hoặc tương tự, bạn có thể sử dụng các yêu cầu tính năng của hệ thống mô-đun Racket.

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

Đây only-in có nghĩa là chỉ các ràng buộc chúng tôi chỉ định sẽ được nạp, đây là apply từ được xây dựng trong mô-đun racket.

Chúng tôi cũng có thể sử dụng rename-in thay vì only-in, nhưng kể từ khi mô-đun racket luôn nạp như một phần của ngôn ngữ vợt, chúng ta không cần phải tái nhập khẩu tất cả của nó và do đó chỉ cần sử dụng only-in.