【问题标题】:Parent eval (reader) function in Clojure source?Clojure源代码中的父评估(阅读器)函数?
【发布时间】:2012-05-05 13:20:20
【问题描述】:

在第 7 章的Peter Norvig's 史诗巨著Paradigms of Artifical Intelligence Programming 中,他描述了一个函数interp,它实际上是一个简单的eval 函数,用于解释REPL 中的基本Scheme。

(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 函数?我认为它在某处的阅读器代码中。

【问题讨论】:

    标签: clojure scheme eval


    【解决方案1】:

    你的意思是,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 类中的 eval 方法(在上面的 sn-p 中引用,并驻留在 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 程序是有道理的 - 就像问题中引用的代码中的大小写。

    【讨论】:

    • OP 现在非常失望——他发现了 Clojure 的肮脏秘密,即 eval 不是 Clojure :)
    • @MarkoTopolnik 确实! .我也是 - 我的意思是,有点失望:/
    • 太好了 - 谢谢。我假设 ClojureScript 没有 eval 函数是正确的吗?这就是我在观看 Rich Hickey ClojureScript 介绍演讲时得到的印象。
    • @hawkeye 没错,ClojureScript 没有 eval。这个post详细解释了原因
    猜你喜欢
    • 1970-01-01
    • 2022-11-14
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多