Clojure源中的parent eval(阅读器)函数? [英] Parent eval (reader) function in Clojure source?

查看:172
本文介绍了Clojure源中的parent eval(阅读器)函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Peter Norvig的史诗作品人工智能程式设计范例在第7章中,他描述了一个函数 interp ,它实际上是一个简单的 eval bare-bones在REPL中的Scheme。

 (defun interp(x& optional env)
解释(评估)环境中的表达式env 。
(cond
((symbolp x)(get-var x env))
((atom x)x)
b(QUOTE(second x))
(BEGIN(last1(mapcar#'(lambda(y)(interp y env))
(rest x))))
set-var!(第二个x)(interp(第三个x)env)env))
(if(interp(second x)env)
b(b(interp(第四个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
x)env)
(mapcar#'(lambda(v)(interp v env))
(rest x))))))))
/ pre>

有趣的是, Christian Queinnec的 Lisp In Small Pieces 具有非常相似的功能,他称之为 eval

  ;;;这是一个天真计划中写的Scheme的天真评估器。 

(define(evaluate e env)
(if(atom?e)
(cond((symbol?e)(lookup e env))
或(数字?e)(字符串?e)(字符?)
(布尔?e)(向量?e))
e)
))
(case(car e)
((quote)(cadr e))
(if) caddr e)env)
(evaluate(cadddr e)env)))
((begin)(eprogn(cdr e)env))
e)env(evaluate(caddr e)env)))
((lambda)(make-function(cadr e)(cddr e)env))
env)
(evlis(cdr e)env))))))

is - 其中Clojure源是等效的 eval / interp function?我认为它是在读者代码某处。

解决方案

你的意思是,Clojure的 eval 这将是 clojure.core / eval 。文档中的链接显示了评估的发生情况:




  • 在REPL中交互式

  • 通过加载或加载文件从流中读取的一系列表单上读取

  • 以编程方式,通过 eval



如果您对源代码,请查看Clojure的 core.clj 文件。特别是 eval 的代码如下:

  eval 
评估表单数据结构(不是文本!)并返回结果
[form](。clojure.lang.Compiler(eval form)))

反过来, Compiler 类(在上述代码段中引用,并且位于Compiler.java 文件)如下所示:

  public static Object eval )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 instance of IPersistentCollection
&&!(RT.first(form)symbolof
& )。)name.startsWith(def)))
{
FnExpr fexpr =(FnExpr)analyze(C.EXPRESSION,RT.list(FN,PersistentVector.EMPTY,form) );
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(!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程序发生是有意义的 - 如问题中引用的代码中的情况。


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.

解决方案

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.

这篇关于Clojure源中的parent eval(阅读器)函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆