2012-05-05 47 views
5

在第7章Peter Norvig's史詩鉅著Paradigms of Artifical Intelligence Programming - 他描述了一個功能interp這實際上是解釋在REPL一個最基本的計劃時使用一個簡單的eval功能。Clojure源中的父eval(reader)函數?

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

有趣的是 - 的Christian Queinnec'sLisp In Small Pieces開篇有一個非常類似的功能,他稱之爲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)))))) 

我的問題是 - 哪裏是Clojure的來源是相當於eval/interp功能?我假設它在讀者代碼的某處。

回答

6

你的意思是,什麼是Clojure的eval程序?那會是clojure.core/eval。此link從文檔顯示瞭如何評價發生:

  • 交互,在REPL
  • 基於從流中讀取的形式的序列,經由負載或負載文件
  • 編程,經由eval

如果您對的實際源代碼感興趣,請查看Clojure的core.clj文件。特別地,對於eval代碼看起來是這樣的:

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

反過來,從Compiler類(在上面的代碼段中引用,和居住在Compiler.java文件)的eval方法看起來像這樣:

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(); 
     } 
} 

我想這不像你期望的那樣,但考慮到Clojure運行在JVM之上的事實,評估部分作爲Java程序而不是Lisp程序發生是有意義的 - 就像在問題中引用的代碼中。

+1

OP現在非常失望 - 他發現了Clojure的骯髒祕密,eval不是Clojure :) –

+0

@MarkoTopolnik確實! 。我也是 - 我的意思是有點失望:/ –

+0

太好了 - 謝謝你。假設ClojureScript沒有eval函數,我會正確嗎?這是我從觀看Rich Hickey ClojureScript介紹講話中得到的印象。 – hawkeye