2012-05-05 8 views
5

En Peter Norvig's tomo épico Paradigms of Artifical Intelligence Programming en el Capítulo 7 - él describe una función interp que es efectivamente una función eval simple utilizada al interpretar un Esquema escueto en un REPL.Función de evaluación de padres (lector) en la fuente de Clojure?

(defun interp (x &optional env) 
    "Interpret (evaluate) the expression x in the environment env." 
    (cond 
    ((symbolp x) (get-var x env)) 
    ((atom x) x) 
    ((case (first x) 
     (QUOTE (second x)) 
     (BEGIN (last1 (mapcar #'(lambda (y) (interp y env)) 
           (rest x)))) 
     (SET! (set-var! (second x) (interp (third x) env) env)) 
     (IF  (if (interp (second x) env) 
        (interp (third x) env) 
        (interp (fourth x) env))) 
     (LAMBDA (let ((parms (second x)) 
        (code (maybe-add 'begin (rest2 x)))) 
       #'(lambda (&rest args) 
        (interp code (extend-env parms args env))))) 
     (t  ;; a procedure application 
       (apply (interp (first x) env) 
         (mapcar #'(lambda (v) (interp v env)) 
           (rest x)))))))) 

Curiosamente - la apertura del Capítulo Christian Queinnec'sLisp In Small Pieces tiene una función muy similar, lo llama eval.

;;; This is a naive evaluator for Scheme written in naive Scheme. 

(define (evaluate e env) 
    (if (atom? e) 
     (cond ((symbol? e) (lookup e env)) 
      ((or (number? e) (string? e) (char? e) 
       (boolean? e) (vector? e)) 
      e) 
      (else (wrong "Cannot evaluate" e))) 
     (case (car e) 
     ((quote) (cadr e)) 
     ((if)  (if (evaluate (cadr e) env) 
         (evaluate (caddr e) env) 
         (evaluate (cadddr e) env))) 
     ((begin) (eprogn (cdr e) env)) 
     ((set!) (update! (cadr e) env (evaluate (caddr e) env))) 
     ((lambda) (make-function (cadr e) (cddr e) env)) 
     (else  (invoke (evaluate (car e) env) 
          (evlis (cdr e) env)))))) 

Mi pregunta es - ¿dónde está la fuente de Clojure es el equivalente a la función eval/interp? Supongo que está en el código del lector en alguna parte.

Respuesta

6

Quieres decir, ¿cuál es el procedimiento de Clojure eval? Eso sería clojure.core/eval. Este link de la documentación muestra cómo se produce la evaluación:

  • de forma interactiva, en el REPL
  • En una secuencia de formas leídos de una corriente, a través de la carga o de carga de archivos
  • mediante programación, a través de eval

Si está interesado en el código fuente real, eche un vistazo al archivo core.clj de Clojure. En particular, el código para eval se ve así:

(defn eval 
    "Evaluates the form data structure (not text!) and returns the result." 
    [form] (. clojure.lang.Compiler (eval form))) 

A su vez, el método eval de la clase Compiler (referencia en el fragmento anterior, y que residen en el archivo Compiler.java) tiene el siguiente aspecto:

public static Object eval(Object form) throws Exception{ 
    boolean createdLoader = false; 
    if(true)//!LOADER.isBound()) 
     { 
     Var.pushThreadBindings(RT.map(LOADER, RT.makeClassLoader())); 
     createdLoader = true; 
     } 
    try 
     { 
     Integer line = (Integer) LINE.deref(); 
     if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY)) 
      line = (Integer) RT.meta(form).valAt(RT.LINE_KEY); 
     Var.pushThreadBindings(RT.map(LINE, line)); 
     try 
      { 
      form = macroexpand(form); 
      if(form instanceof IPersistentCollection && Util.equals(RT.first(form), DO)) 
       { 
       ISeq s = RT.next(form); 
       for(; RT.next(s) != null; s = RT.next(s)) 
        eval(RT.first(s)); 
       return eval(RT.first(s)); 
       } 
      else if(form instanceof IPersistentCollection 
        && !(RT.first(form) instanceof Symbol 
         && ((Symbol) RT.first(form)).name.startsWith("def"))) 
       { 
       FnExpr fexpr = (FnExpr) analyze(C.EXPRESSION, RT.list(FN, PersistentVector.EMPTY, form), "eval"); 
       IFn fn = (IFn) fexpr.eval(); 
       return fn.invoke(); 
       } 
      else 
       { 
       Expr expr = analyze(C.EVAL, form); 
       return expr.eval(); 
       } 
      } 
     finally 
      { 
      Var.popThreadBindings(); 
      } 
     } 
    catch(Throwable e) 
     { 
     if(!(e instanceof CompilerException)) 
      throw new CompilerException((String) SOURCE.deref(), (Integer) LINE.deref(), e); 
     else 
      throw (CompilerException) e; 
     } 
    finally 
     { 
     if(createdLoader) 
      Var.popThreadBindings(); 
     } 
} 

Supongo que no es exactamente lo que esperabas, pero dado que Clojure se ejecuta sobre la JVM, tiene sentido que la parte de evaluación ocurra como un programa Java y no como un programa Lisp, como es el caso en el código al que se hace referencia en la pregunta.

+1

OP ahora está muy decepcionado - descubrió el secreto sucio de Clojure que eval no es Clojure :) –

+0

@MarkoTopolnik ¡De hecho! . Y también lo estoy, quiero decir, un poco decepcionado:/ –

+0

Genial, gracias por esto. ¿Sería correcto suponer que ClojureScript no tiene una función eval? Esa fue la impresión que tuve de ver la introducción de Rich Hickey ClojureScript. – hawkeye

Cuestiones relacionadas