Parent eval (reader) function in Clojure source?

柔情痞子 提交于 2019-12-13 13:13:06

问题


In Peter Norvig's epic tome Paradigms of Artifical Intelligence Programming in Chapter 7 - he describes a function interp which is effectively a simple eval function used when interpreting a bare-bones Scheme in a REPL.

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

Interestingly enough - the opening Chapter of Christian Queinnec's Lisp In Small Pieces has a very similar function, he calls it 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) )) ) ) )

My question is - where is the Clojure source is the equivalent eval/interp function? I assume it is in the reader code somewhere.


回答1:


You mean, what's Clojure's eval procedure? That'd be clojure.core/eval. This link from the documentation shows how evaluation occurs:

  • Interactively, in the REPL
  • On a sequence of forms read from a stream, via load or load-file
  • Programmatically, via eval

If you're interested in the actual source code, take a look at Clojure's core.clj file. In particular, the code for eval looks like this:

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

In turn, the eval method from the Compiler class (referenced in the above snippet, and residing in the Compiler.java file) looks like this:

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

I guess that's not quite what you expected it to be, but given the fact that Clojure runs on top of the JVM, it makes sense that the evaluation part occurs as a Java program and not as a Lisp program - as is the case in the code referenced in the question.



来源:https://stackoverflow.com/questions/10462262/parent-eval-reader-function-in-clojure-source

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!