2012-05-05 29 views
5

Trong Peter Norvig's tome hoành tráng Paradigms of Artifical Intelligence Programming trong Chương 7 - ông mô tả chức năng interp có hiệu quả là chức năng đơn giản eval được sử dụng khi diễn giải Sơ đồ xương trần trong REPL.Chức năng eval (reader) của cha mẹ trong nguồn 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)))))))) 

Điều thú vị là đủ - khai mạc Chương của Christian Queinnec'sLisp In Small Pieces có một chức năng rất giống nhau, ông gọi nó 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)))))) 

Câu hỏi của tôi là - nơi được nguồn Clojure là tương đương eval/interp chức năng? Tôi cho rằng nó nằm trong mã người đọc ở đâu đó.

Trả lời

6

Ý của bạn là thủ tục eval của Clojure là gì? Đó là clojure.core/eval. link này từ các tài liệu cho thấy đánh giá xảy ra như thế nào:

  • tương tác, trong REPL
  • Trên một chuỗi các hình thức đọc từ một dòng suối, qua tải hoặc tải tập tin
  • lập trình, thông qua eval

Nếu bạn quan tâm đến mã nguồn thực tế, hãy xem tập tin core.clj của Clojure. Đặc biệt, các mã cho eval trông như thế này:

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

Đến lượt mình, các eval phương pháp từ lớp Compiler (tham chiếu trong đoạn mã trên, và cư trú trong file Compiler.java) trông như thế này:

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

Tôi đoán đó không phải là những gì bạn mong đợi, nhưng với thực tế là Clojure chạy trên đầu trang của JVM, nó có ý nghĩa rằng phần đánh giá xảy ra như một chương trình Java và không phải là một chương trình Lisp - như là trường hợp trong mã được tham chiếu trong câu hỏi.

+1

OP giờ đây rất thất vọng - anh đã phát hiện ra bí mật bẩn của Clojure mà eval không phải là Clojure :) –

+0

@MarkoTopolnik Thật vậy! . Và tôi cũng vậy - Ý tôi là, một chút thất vọng:/ –

+0

Tuyệt vời - cảm ơn vì điều này. Tôi có đúng khi giả định rằng ClojureScript không có hàm eval? Đó là ấn tượng mà tôi nhận được khi xem buổi nói chuyện giới thiệu Rich Hickey ClojureScript. – hawkeye

Các vấn đề liên quan