Clojure源中的父级评估(阅读器)功能?

时间:2012-05-05 13:20:20

标签: clojure scheme eval

在第7章的Peter Norvig's史诗大片Paradigms of Artifical Intelligence Programming中 - 他描述了一个函数interp,它实际上是一个简单的eval函数,用于解释一个简单的方案。 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))))))))

有趣的是 - Christian Queinnec's 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源在哪里是等效的eval / interp函数?我假设它在某处的读者代码中。

1 个答案:

答案 0 :(得分:6)

你的意思是,什么是Clojure的eval程序?那是clojure.core/eval。文档中的link显示了评估的发生方式:

  • 互动,在REPL
  • 在从流中读取的一系列表单中,通过load或load-file
  • 以编程方式,通过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之上运行这一事实,评估部分作为Java程序而不是作为Lisp程序发生是有意义的 - 就像是问题中引用的代码中的大小写。