我怎样才能在这个函数中保持数学顺序?
Posted
技术标签:
【中文标题】我怎样才能在这个函数中保持数学顺序?【英文标题】:How can I keep the mathematical order in this function? 【发布时间】:2022-01-05 21:00:39 【问题描述】:我有这个函数返回错误的结果
def calc(a): return lambda op:
'+': lambda b: calc(a+b),
'-': lambda b: calc(a-b),
'*': lambda b: calc(a*b),
'/': lambda b: calc(a/b),
'=': a[op]
calc(1)('+')(2)('*')(10)('=') # 30 -> should be 21
有谁知道如何保持函数式风格并遵循正确的数学顺序?
【问题讨论】:
如果你正在寻找柯里化,Haskell 基本上是围绕这个概念构建的,而 Python 则完全没有。您可能可以自己实现它,但它不值得痛苦,IMOadd(1, mul(2, 10))
。不要试图在你的表达式中镜像中缀符号。 (add
和 mul
是在 operator
模块中预定义的,以及其他运算符的函数。)
Python 不是函数式语言。您可以使用lambda
函数和map
和reduce
编写一些功能性代码,但仅此而已。如果您想要一种纯函数式的方法,那么您正在寻找 Haskell。我认为还有其他纯函数式语言,但 Python 不是其中之一。同样,您可以在 Python 中模拟函数式样式,但这就像用叉子吃汤一样 - 不是非常有效或富有成效。
@KellyBundy,我不确定柯里化是否与运算符优先级有很大关系。 AFAIK,运算符优先级是在解析期间完成的,但currying是在运行时完成的。如果您以正确的顺序调用柯里化函数,您将获得正确的运算符优先级。
因为a
也可以是一个子表达式,你可以简单地写成calc(1)('+')(calc(2)('*')(10)('='))('=')
。否则,您需要为每个运算符分配优先级并累积传递给calc
的所有运算符(在评估之前),以按优先级确定的顺序排列它们。此外,您还必须将括号作为复合运算符引入。对于一个有趣的项目来说,这可能是太多工作了..
【参考方案1】:
请注意,我对 Python 缺乏深入的了解,因此答案将在 JS 中。希望它仍然有帮助。
一个合适的解决方案需要涵盖以下属性:
运算符优先级 运算符关联性(左/右/无) 运算符数量(一元/二元) 圆括号运算符关联性不得与数学属性相混淆。运算符必须是左、右或根本不关联。后者意味着操作符是不可组合的。
优先级决定了不同运算符的计算顺序,如果相同则关联。
a + b - c = a + (b - c) :: - exceeds precedence of +
a - b - c = (a - b) - c :: - is left associative
这个解决方案只是一个粗略的草图。它不使用字符串符号作为运算符,但可以轻松更改。更重要的是,它既不考虑运算符结合性也不考虑括号,而是始终假定左结合性和二元运算符。这只是开始了解预期的复杂性:
const prec = n => o => (o.prec = n, o);
const prec1 = prec(1);
const prec2 = prec(2);
const prec3 = prec(3);
const prec4 = prec(4);
const add = prec1(x => prec1(y => x + y));
const sub = prec2(x => prec2(y => x - y));
const mul = prec3(x => prec3(y => x * y));
const div = prec4(x => prec4(y => x / y));
const infix = x => f => infix_(f(x));
const infix_ = partialF => y =>
const go = g =>
if (partialF.prec >= g.prec)
return infix_(g(partialF(y)));
else
const partialG = g(y);
return infix_(z => partialF(partialG(z)));
;
Object.defineProperty(
go,
"run",
get() return partialF(y)); // lazy property getter
return go;
;
const r1 = infix(2) (mul) (3) (sub) (4) (add) (5) (div) (2); // 2*3-4+5/2 = 4.5
const r2 = infix(2) (add) (3) (sub) (4) (mul) (5) (div) (2); // 2+3-4*5/2 = -5
console.log(r1.run);
console.log(r2.run);
【讨论】:
以上是关于我怎样才能在这个函数中保持数学顺序?的主要内容,如果未能解决你的问题,请参考以下文章
轮询:页面被刷新,任何指定的过滤器/排序顺序也被重置。我怎样才能防止这种情况发生?