2011-08-24 12 views
8

Estoy intentando ejecutar el programa descrito en SICP 4.1 (http://mitpress.mit.edu/sicp/full-text/book/book-ZH-26.html) pero se encontraron con algunas dificultades para redefinir la función apply, como el libro sugiere que lo haga. El código es el siguiente:Cómo ejecutar el Evaluador Metacircular en 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) 

El problema es el principio, cuando estoy tratando de guardar la combinación integrados La aplicar como "aplicar-in-esquema subyacente." Como hay otra función llamada "aplicar" escrita a continuación, obtengo el error "referencia a un identificador antes de su definición: aplicar". ¿Cómo puedo hacer referencia al builtin "aplicar" sin causar un error aquí?

Respuesta

7

Puede cambiar el nombre de la función que SICP llama a apply a metacircular-apply o algo así. No es necesario que se llame apply que no sea estética.

1

utilizo la siguiente cabecera, que renombra aplica a aplicar-in-subyace-esquema:

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

Aunque no se puede redefinir una definición en el lenguaje de la raqueta #lang racket o similares, puede utilizar la requieren característica del sistema de módulos de Racket.

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

Aquí only-in significa que sólo los enlaces que especificamos serán cargados, siendo aquí apply desde el módulo integrado racket.

También podríamos utilizar en lugar de rename-inonly-in, pero desde el módulo racket siempre se carga como parte del lenguaje de la raqueta, que no tenga que volver a importar todos de la misma y por lo tanto sólo tiene que utilizar only-in.

Cuestiones relacionadas