#python #functional-programming
#питон #функциональное программирование
Вопрос:
У меня есть эта функция, которая возвращает неправильный результат
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 -gt; should be 21
У кого-нибудь есть идея, как я могу сохранить функциональный стиль и следовать правильному математическому порядку?
Комментарии:
1. Если вы ищете карри, Haskell в основном построен на этой концепции, в то время как Python ее вообще не имеет. Вероятно, вы можете реализовать это самостоятельно, но это не стоит такой боли, ИМО
2.
add(1, mul(2, 10))
. Не пытайтесь отразить инфиксную нотацию в своем выражении лица. (add
иmul
предопределены вoperator
модуле, а также функции для других операторов.)3. Python не является функциональным языком. Вы можете написать несколько функциональный код с
lambda
функциями иmap
иreduce
, но это почти все. Если вам нужен чисто функциональный подход, вы ищете Хаскелла. Я думаю, что есть и другие чисто функциональные языки, но Python не входит в их число. Опять же, вы можете имитировать функциональный стиль в Python, но это все равно, что использовать вилку для супа — не очень эффективно или продуктивно.4. @KellyBundy, я не уверен, имеет ли каррирование большое отношение к приоритету операторов. AFAIK, приоритет оператора выполняется во время синтаксического анализа, но каррирование выполняется во время выполнения. Если вы вызываете функции карри в правильном порядке, вы получите правильный приоритет оператора.
5. Поскольку
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 =gt; o =gt; (o.prec = n, o); const prec1 = prec(1); const prec2 = prec(2); const prec3 = prec(3); const prec4 = prec(4); const add = prec1(x =gt; prec1(y =gt; x y)); const sub = prec2(x =gt; prec2(y =gt; x - y)); const mul = prec3(x =gt; prec3(y =gt; x * y)); const div = prec4(x =gt; prec4(y =gt; x / y)); const infix = x =gt; f =gt; infix_(f(x)); const infix_ = partialF =gt; y =gt; { const go = g =gt; { if (partialF.prec gt;= g.prec) return infix_(g(partialF(y))); else { const partialG = g(y); return infix_(z =gt; 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);