如何检测函数是否是最后一个被调用

时间:2018-04-13 08:39:00

标签: javascript function parsing functional-programming

我必须做一个数学表达式'评估者通过使用add,subtract,cnst(代表常量)或带有一个或两个参数的变量等函数,取决于我们需要什么样的操作:一元或二元。以下是我所谈论的一个例子:

let expression = add(cnst(2), add(cnst(2), variable("x")));

表达式必须是一个函数,因此我们只需调用expression(3)并获得结果:7。

我的想法是返回数字或变量的字符串表示,如果它是关于常量或变量的,并返回第一个参数,操作和第二个参数的字符串连接,如果它是关于二进制操作的。但是,我们需要使结果成为一个函数。所以,我认为返回一个函数会很好:

evaluate(x) {
    return eval(expr);
} 

如果此次通话最后。我的意思是,在上面的示例中,所有内部函数都应该返回' 2'' 2'' x',' 2 + x'但外部的(添加)应该返回'评估'并设置全局值' expr'在这种情况下需要什么(' 2 + 2 + x')。那么,是否可以检测外部是否添加'在所有其他功能之后被召唤?

1 个答案:

答案 0 :(得分:1)

这有点棘手,但如果使用Object.defineProperty()重新定义函数的预期arguments.length,则可以返回每个级别的函数并检查其长度值以确定操作数是否需要变量:

function consume(vars) {
  return (arg) => arg(...vars.splice(0, arg.length));
}

function op(f) {
  return (...args) => {
    return Object.defineProperty((...vars) => {
      return f(...args.map(consume(vars)));
    }, 'length', {
      value: args.reduce((a, b) => a + b.length, 0)
    });
  };
}

const add = op((a, b) => a + b);
const sub = op((a, b) => a - b);
const cnst = (v) => () => v;
const variable = () => (v) => v;

let e1 = add(cnst(2), add(cnst(2), variable("x")));
let e2 = add(cnst(5), sub(variable("x"), variable("y")));

console.log(e1(5)); // 2 + (2 + 5)
console.log(e2(6, 3)); // 5 + (6 - 3)

缺点是您无法通过此方法通过标签指定参数。为此,您可以将对象作为参数传递给表达式:

const op = (f) => (...args) => (o = {}) => f(...args.map(arg => arg(o)));

const add = op((a, b) => a + b);
const sub = op((a, b) => a - b);
const cnst = (v) => () => v;
const variable = (label) => (o) => o[label];

let e1 = add(cnst(2), add(cnst(2), variable("x")));
let e2 = add(cnst(5), sub(variable("x"), variable("y")));

console.log(e1({ x: 5 })); // 2 + (2 + 5)
console.log(e2({ x: 6, y: 3 })); // 5 + (6 - 3)

最后,如果你想要一个interop,你可以在其中指定一个像普通函数一样的args并将它们映射到变量名,你可以添加另一个名为args()的表达式类型,它定义了这样的映射:

const op = (f) => (...args) => (o = {}) => f(...args.map(arg => arg(o)));

const args = (map) => (e) => (...args) => e(map(...args));
const add = op((a, b) => a + b);
const sub = op((a, b) => a - b);
const cnst = (v) => () => v;
const variable = (label) => (o) => o[label];

let a1 = args(x => ({ x }));
let e1 = a1(add(cnst(2), add(cnst(2), variable("x"))));

let a2 = args((x, y) => ({ x, y }));
let e2 = a2(add(cnst(5), sub(variable("x"), variable("y"))));

console.log(e1(5)); // 2 + (2 + 5)
console.log(e2(6, 3)); // 5 + (6 - 3)