我需要一些关于我应该如何在 JavaScript 中实现和实现嘴唇的延续(我的 lisp 几乎就像方案,除了没有延续和 TOC)。
这是我的评估功能:
function getFunctionArgs(rest, { env, dynamic_scope, error }) {
var args = [];
var node = rest;
markCycles(node);
while (true) {
if (node instanceof Pair && !isEmptyList(node)) {
var arg = evaluate(node.car, { env, dynamic_scope, error });
if (dynamic_scope) {
arg = unpromise(arg, arg => {
if (typeof arg === 'function' && isNativeFunction(arg)) {
return arg.bind(dynamic_scope);
}
return arg;
});
}
args.push(arg);
if (node.haveCycles('cdr')) {
break;
}
node = node.cdr;
} else {
break;
}
}
return resolvePromises(args);
}
// -------------------------------------------------------------------------
function evaluateMacro(macro, code, eval_args) {
if (code instanceof Pair) {
//code = code.clone();
}
var value = macro.invoke(code, eval_args);
return unpromise(resolvePromises(value), function ret(value) {
if (value && value.data || !value || selfEvaluated(value)) {
return value;
} else {
return quote(evaluate(value, eval_args));
}
});
}
// -------------------------------------------------------------------------
function evaluate(code, { env, dynamic_scope, error = () => {} } = {}) {
try {
if (dynamic_scope === true) {
env = dynamic_scope = env || global_env;
} else if (env === true) {
env = dynamic_scope = global_env;
} else {
env = env || global_env;
}
var eval_args = { env, dynamic_scope, error };
var value;
if (isNull(code)) {
return code;
}
if (isEmptyList(code)) {
return emptyList();
}
if (code instanceof Symbol) {
return env.get(code, { weak: true });
}
var first = code.car;
var rest = code.cdr;
if (first instanceof Pair) {
value = resolvePromises(evaluate(first, eval_args));
if (isPromise(value)) {
return value.then((value) => {
return evaluate(new Pair(value, code.cdr), eval_args);
});
// else is later in code
} else if (typeof value !== 'function') {
throw new Error(
type(value) + ' ' + env.get('string')(value) +
' is not a function while evaluating ' + code.toString()
);
}
}
if (first instanceof Symbol) {
value = env.get(first, { weak: true });
if (value instanceof Macro) {
var ret = evaluateMacro(value, rest, eval_args);
return unpromise(ret, result => {
if (result instanceof Pair) {
return result.markCycles();
}
return result;
});
} else if (typeof value !== 'function') {
if (value) {
var msg = `${type(value)} \`${value}' is not a function`;
throw new Error(msg);
}
throw new Error(`Unknown function \`${first.name}'`);
}
} else if (typeof first === 'function') {
value = first;
}
if (typeof value === 'function') {
var args = getFunctionArgs(rest, eval_args);
return unpromise(args, function(args) {
var scope = dynamic_scope || env;
var result = resolvePromises(value.apply(scope, args));
return unpromise(result, (result) => {
if (result instanceof Pair) {
return quote(result.markCycles());
}
return result;
}, error);
});
} else if (code instanceof Symbol) {
value = env.get(code);
if (value === 'undefined') {
throw new Error('Unbound variable `' + code.name + '\'');
}
return value;
} else if (code instanceof Pair) {
value = first && first.toString();
throw new Error(`${type(first)} ${value} is not a function`);
} else {
return code;
}
} catch (e) {
error && error(e, code);
}
}
笔记:
// unpromise and resolvePromises is just used ot unwrap any promise
// inside list and return new promise for whole expression if found
// any promise and not found it just return value as is
// markCycles is used to prevent of recursive printing of list cycles
// if you create graph cycles using `set-cdr!` or `set-car!`
在评估延续的表达式时是否需要创建堆栈?我怎样才能做到这一点?我以为我以某种方式创建Continuation
了一个类,该类将处于两种模式中about 而不是评估调用延续的表达式之前的代码,例如:
(* 10 (cont 2))
(* 10 x)
需要被忽略
我也不确定我应该如何着手和创建call/cc
函数。它是否应该返回一些中间数据结构,并将其参数存储在该数据结构中,以便可以通过继续评估来调用它?
'call/cc': function(lambda) {
return new CallCC(lambda);
}
如果 eval 找到 CallCC 的实例,它会继续(不确定如何)使用
if (value instanceof CallCC) {
value.call(new Continuation(stack));
}
你会这样做吗?所以通常我的问题是关于堆栈的。是否需要继续?如果需要,那么应该如何创建它?
我发现这篇文章Writing a Lisp: Continuations展示了如何实现延续,但很难理解,因为它在 Haskell 中。