5

Peter Norvig の叙事詩本Paradigms of Artifical Intelligence Programmingの第 7 章で、彼は、REPL で必要最小限のスキームを解釈するときに使用されるinterp事実上単純な関数である関数について説明しています。eval

(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 の Lisp 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 のソースはどこにあるのですevalinterp? リーダーコードのどこかにあると思います。

4

1 に答える 1

6

つまり、Clojureのeval手順は何ですか?それはclojure.core/evalになります。ドキュメントからのこのリンクは、評価がどのように行われるかを示しています。

  • インタラクティブに、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)))

次に、クラスのevalメソッドCompiler(上記のスニペットで参照され、Compiler.javaファイルにある)は次のようになります。

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上で実行されるという事実を考えると、評価部分はLispプログラムとしてではなくJavaプログラムとして行われることは理にかなっています-質問で参照されているコード。

于 2012-05-05T13:31:11.947 に答える