对Lisp s表达式的平坦评估

时间:2012-10-21 06:55:42

标签: c lisp eval s-expression

我正在试图弄清楚如何实现Lisp评估 的非递归即可。我的基于C的评估者是Minimal Lisp文件l1.c.然而 那里的几个函数再次进入eval:eval,apply, evargs,evlist以及Lisp Ops defineFunc,whileFunc,setqFunc,ifFunc ...

我正在尝试找出持平的评估。 我可以提出一些可行的方法:

  1. 转换为字节代码并在VM中执行
  2. 实施一个平面的Forth评估器并在Forth中实现Lisp评估,这是lf.f所做的。
  3. 另一种可能性是将l1.c中的所有递归函数连接到一个大的开关循环中。局部变量将连接到基于堆的结构中,对递归子函数的调用将由基于堆的返回堆栈实现。
  4. 我的问题是:是否有算法/论文/实施 以不同方式做平面评估。我正在寻找 一个不转换为字节码的实现 类似于使用a的无递归“深度优先遍历” 下推堆栈。我想对原始的s表达式进行操作。

    答案:在c中实现评估器时,需要实现整体 在扁平循环中,手动实现返回堆栈和堆栈框架,使用goto和switch()对控制流进行建模。以下是一个示例:flat

5 个答案:

答案 0 :(得分:4)

Lisp的一个非常重要的方面,实际上是许多函数式语言的一个重要方面,它是 compositional 。这意味着表达式的含义是使用其子表达式的含义来定义的 - 换句话说,评估的定义本质上是递归的。在非函数式语言中,表达式与语句之间存在一些差异,但即使表达式也不以某种方式限制,因此递归也被引入定义。可能只是语言定义的递归性不那么明显的唯一情况是汇编语言。 (尽管有意义的定义当然需要归纳。)

因此,对eval的一些递归定义的争论是你将失去的。如果你使用编译到机器代码,那么代码将是递归的(并且生成代码也将是递归的)。如果您通过Forth评估程序进行评估,那么该评估程序仍将是递归的。即使你在另一个答案中使用了CPS建议,你最终还是会有另一个堆栈编码。

所以最重要的是你可以得到的最好的是一些不直接使用机器堆栈的堆栈编码 - 没有实质性区别,但你通常会失去性能(因为CPU处理 < / em>非常有效地堆栈,并且它在堆上的编码会变得更慢。)

答案 1 :(得分:3)

请参阅此主题:Continuation Passing Style

答案 2 :(得分:2)

在C中实现Lisp-evaluationator时,C编译器使用堆栈 生成子程序调用的控制流程。实现无堆栈 C语言中的求值器需要使用goto和。手动编写控制流 开关():

v *
evargs(ctx *cctx, v *l, v *env)
{
    struct v *r = 0;
    if (l) {
        r = eval(cctx, car(l),env);
        r =  mkCons(r,evargs(cctx, cdr(l),env));
    }
    return r;
}

case EVARGS_0:
    S_SET(0,0);                         /* EVARGS_0: r = 0; */ 
    if (!(v=S(2)))                      /* if (l) */
        goto ret;
    RCALL_EVAL(EVARGS_1, car(v));       /* r = < eval(cctx, car(l),env); > */
    break;    
case EVARGS_1:
    S_SET(3,S(1));                      /* EVARGS_1: < r = ... > */
    RCALL_EVARGS(EVARGS_2, cdr(S(2)));  /*  r =  mkCons(r, < evargs(cctx, cdr(l),env) > ); */
    break;
case EVARGS_2:
    S_SET(0,mkCons(S(3),S(1)));         /* EVARGS_2: < r =  mkCons(r,  evargs(cctx, cdr(l),env)  ); > */
    goto ret;

答案 3 :(得分:0)

我认为您可能缺少的关键洞察力是在lisp解释器中,最小的一组函数被实现为非递归的基元。确切的原语集有所不同,但包括cons,car,cdr和apply的“最原始”版本,它执行这些实际函数之一而不是自身的解释版本。

你应该查阅John McCarthy的原始论文和/或John Allen的Lisp 1.5

答案 4 :(得分:0)

我记得有一本关于HOPE编程语言的书。它是一种类似于ML的功能语言。它对编译器进行了全面的概念性描述,并对函数式语言编译器提出了一般性的看法。一个观察结果是关于Y-combinator的争论。作者提出,处理递归函数的一种可能方法是Y-combinator的实现,并将每个递归函数转换为可以使用Y-combinator重现的非递归函数。

这将是if特殊形式的类似技巧,它为语言中可能需要的各种惰性评估提供(通常也足够)。以类似的方式,您可以限制所有函数的递归,但引入了一个特殊的Y函数,允许递归开始。