JavaScript中的Lisp宏引用实现 [英] Lisp macros quotation implementation in JavaScript

查看:90
本文介绍了JavaScript中的Lisp宏引用实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 JavaScript中像lisp这样的基本方案,并且反引号有问题并引用宏,它们会评估符号是否位于数组的第一个元素(如

I have basic scheme like lisp in JavaScript and have problem with backquote and quote macros, they evaluate symbols if they are at first element of the array like

> `(foo 10)

给出错误foo not found

适用于这样的代码

> (define x '(1 2 3))
> (print `(1 2 ,@x 4 5))

我的评估函数看起来像这样:

my eval function look like this:

function evaluate(code, env) {
  env = env || global_env;
  var value;
  if (typeof code === 'undefined') {
    return;
  }
  var first = code.car;
  var rest = code.cdr;
  if (first instanceof Pair) {
    value = evaluate(first, env);
  }
  if (typeof first === 'function') {
    value = first;
  }
  if (first instanceof Symbol) {
    value = env.get(first);
    if (value instanceof Macro) {
      return evaluate(value.invoke(rest, env), env);
    } else if (typeof value !== 'function') {
      throw new Error('Unknown function `' + first.name + '\'');
    }
  }
  if (typeof value === 'function') {
    var args = [];
    var node = rest;
    while (true) {
      if (node instanceof Pair) {
        args.push(evaluate(node.car, env));
        node = node.cdr;
      } else {
        break;
      }
    }
    var promises = args.filter((arg) => arg instanceof Promise);
    if (promises.length) {
      return Promise.all(args).then((args) => {
        return value.apply(env, args);
      });
    }
    return value.apply(env, args);
  } else if (code instanceof Symbol) {
    value = env.get(code);
    if (value === 'undefined') {
      throw new Error('Unbound variable `' + code.name + '\'');
    }
    return value;
  } else {
    return code;
  }
}

我的宏我只是一个函数,它返回Pair的实例,该实例与要评估的输入和代码参数相同,env是Environment的实例,该实例具有获取函数的函数,该函数返回函数或变量.

my Macro i just a function that return instance of Pair which is the same as input and code argument to evaluate, env is a instance of Environment that have function get that return functions or variables.

准引用的宏如下所示:

  quasiquote: new Macro(function(arg) {
    var env = this;
    function recur(pair) {
      if (pair instanceof Pair) {
        var eval_pair;
        if (Symbol.is(pair.car.car, 'unquote-splicing')) {
          eval_pair = evaluate(pair.car.cdr.car, env);
          if (!eval_pair instanceof Pair) {
            throw new Error('Value of unquote-splicing need to be pair')
          }
          if (pair.cdr instanceof Pair) {
            if (eval_pair instanceof Pair) {
              eval_pair.cdr.append(recur(pair.cdr));
            } else {
              eval_pair = new Pair(eval_pair, recur(pair.cdr));
            }
          }
          return eval_pair;
        }
        if (Symbol.is(pair.car, 'unquote-splicing')) {
          eval_pair = evaluate(pair.cdr.car, env);
          if (!eval_pair instanceof Pair) {
            throw new Error('Value of unquote-splicing need to be pair')
          }
          return eval_pair;
        }
        if (Symbol.is(pair.car, 'unquote')) {
          return evaluate(pair.cdr.car, env);
        }
        var car = pair.car;
        if (car instanceof Pair) {
          car = recur(car);
        }
        var cdr = pair.cdr;
        if (cdr instanceof Pair) {
          cdr = recur(cdr);
        }
        return new Pair(car, cdr);
      }
      return pair;
    }
    return recur(arg.car);
  }),

应该将引号硬编码到评估函数中,不应该处理参数并按原样返回它们吗?那么每个符号的反引号会返回(引用符号)吗?

Should quote be hardcoded into evaluate function, that should not process the arguments and return them as is? Then backquote would return (quote symbol) for each symbol?

推荐答案

准引用的目的是返回可被评估以返回新表单的代码. 例如:

The intent of the quasiquote is to return code that can be evaluated to return a new form. For example:

`(a b ,@list (,c ,d))

...可能会扩展为:

... might expand as:

(append (list 'a 'b) list (list (list c d)))

...,以便在评估过程中产生预期的清单. 您可以找到一些避免分配实际上是常量的列表的方法,例如'(a b)而不是(list 'a 'b),但这意味着不能保证从准引号建立的值总是可修改的.

... so that, during evaluation, it produces the expected list. You could find some ways to avoid allocating lists that are actually constants, like '(a b) instead of (list 'a 'b), but this implies the value built from quasi-quotation cannot be guaranteed to be always modifiable.

但是,您似乎正在运行时扩展宏,在必要时评估其嵌套形式,因此,在您的情况下,每次返回的列表都会不同.在那种情况下,我相信Constant所采用的方法应该可行.

However, you seem to be expanding macros at runtime, evaluating when necessary its nested forms, and so in your case, the returned list will be different each time. In that case, I believe the approach taken with Constant should work.

这篇关于JavaScript中的Lisp宏引用实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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