用堆栈而不是递归实现Lisp-eval
Implementing Lisp eval with a stack instead of recursion
我正在研究如何编写程序.blogspot.com/2010/11/lisp-inintereter-in-90-lines-of-c.html,我想看看如何在没有递归的情况下实现eval()函数,而是作为一个使用堆栈的迭代函数。
以下是来自文章的eval()代码:
////////////////////// eval
cell eval(cell x, environment * env)
{
if (x.type == Symbol)
return env->find(x.val)[x.val];
if (x.type == Number)
return x;
if (x.list.empty())
return nil;
if (x.list[0].type == Symbol) {
if (x.list[0].val == "quote") // (quote exp)
return x.list[1];
if (x.list[0].val == "if") // (if test conseq [alt])
return eval(eval(x.list[1], env).val == "#f" ? (x.list.size() < 4 ? nil : x.list[3]) : x.list[2], env);
if (x.list[0].val == "set!") // (set! var exp)
return env->find(x.list[1].val)[x.list[1].val] = eval(x.list[2], env);
if (x.list[0].val == "define") // (define var exp)
return (*env)[x.list[1].val] = eval(x.list[2], env);
if (x.list[0].val == "lambda") { // (lambda (var*) exp)
x.type = Lambda;
// keep a reference to the environment that exists now (when the
// lambda is being defined) because that's the outer environment
// we'll need to use when the lambda is executed
x.env = env;
return x;
}
if (x.list[0].val == "begin") { // (begin exp*)
for (size_t i = 1; i < x.list.size() - 1; ++i)
eval(x.list[i], env);
return eval(x.list[x.list.size() - 1], env);
}
}
// (proc exp*)
cell proc(eval(x.list[0], env));
cells exps;
for (cell::iter exp = x.list.begin() + 1; exp != x.list.end(); ++exp)
exps.push_back(eval(*exp, env));
if (proc.type == Lambda) {
// Create an environment for the execution of this lambda function
// where the outer environment is the one that existed* at the time
// the lambda was defined and the new inner associations are the
// parameter names with the given arguments.
// *Although the environmet existed at the time the lambda was defined
// it wasn't necessarily complete - it may have subsequently had
// more symbols defined in that environment.
return eval(/*body*/proc.list[2], new environment(/*parms*/proc.list[1].list, /*args*/exps, proc.env));
}
else if (proc.type == Proc)
return proc.proc(exps);
std::cout << "not a functionn";
exit(1);
}
我遇到的第一个问题是想知道如何用堆栈实现"if"逻辑。如果您将条件(第一个单元格)放在堆栈上并进行下一次迭代,您如何知道如何回到您决定是分支到"then"还是"else"单元格/节点的点?
不过,这同样适用于任何其他逻辑:例如,如果我将"define"的单元格放在堆栈上,然后进行下一次迭代,一旦进行了评估,我怎么知道要回到同一个地方?
我已经做了两次了。一次在Common Lisp,一次在Brainfuck。基本思想是将原语和应用程序或推送元素进行堆栈。每个部分都有一个目标,因此评估过程主要依赖于通过地址突变cons细胞。一个例子。#是实际地址而不是符号:
(cons 'a 'b)
#result ->
cons
#x
(#preapply #x 'a 'b)
#result ->
(#preapply #cons 'a 'b) ->
'a
#a
'b
#b
(#apply #cons #a #b)
#result ->
quote
#r
(#preapply #r a)
#a
'b
#b
(#apply #cons #a #b)
#result ->
'b
#b
(#apply #cons #a #b)
#result ->
'b
#b
(#apply #cons a #b)
#result ->
quote
#r
(#preapply #r b)
#b
(#apply #cons a #b)
#result ->
(#preapply #quote b)
#b
(#apply #cons a #b)
#result ->
(#apply #cons a b)
#result ->
<empty stack>
结果(a.b)是在地址为#result的cons的车中找到的。
#preapply是一个处理特殊形式的基元,如if
、lambda
和flambda
。它还推送结构,以便在每个参数是函数时对其求值#application对于基元来说很简单,对于lambdas来说则是栈和环境的手工操作。
在我的实现中,特殊形式和基元函数的地址最低,因此基元只是内存中的一个特殊位置。
相关文章:
- 如何在BST的这个简单递归实现中消除警告
- 使用非递归插入方法实现 AVL 树
- C++ 模板使用递归实现循环
- 了解使用堆栈实现队列的递归调用机制
- 在int main()[c++]中实现一个递归函数
- 链表中的递归长度函数实现
- 递归合并排序算法实现
- 我如何实现递归函数的模板,该模板允许C 中的许多不确定数据类型的参数
- 实现递归函数,避免由 C++ 中 include 的循环调用(没有 #pragma 一次)引起的无限循环输入
- 我应该如何实现递归方法以找到在C++中形成最大堆的多种方法
- 在C++中树的递归实现中少出现1个节点
- 使用递归实现 pow(A, B) % C,其中 A、B 和 C 是正整数
- C++11 递归自旋锁实现
- 在 Matlab 中非递归实现 perms,与 Coder 兼容
- 使用递归函数实现 neper 数 (e)
- GOF复合设计模式CompositeObject::删除C++中的递归实现
- (C++)无递归实现指数函数计算器
- 归并排序递归实现的部分理解
- 迭代方法似乎比递归实现(硬币更换)慢
- 用堆栈而不是递归实现Lisp-eval