I've made nested function that takes 3 separate arguments - each function takes one: (arg1)(operation)(arg2)
def simple_functional_calc(arg1: int):
def inner_functional_calc(operation: str):
import operator
ops = {
' ': operator.add,
'-': operator.sub
}
def inner_inner_functional_calc(arg2: int):
return ops[operation](arg1, arg2)
return inner_inner_functional_calc
return inner_functional_calc
There is also other idea (without imports):
def calculator(arg1: int):
def inner_calc(operation: str):
def add(arg2: int):
return arg1 arg2
def sub(arg2: int):
return arg1 - arg2
if operation == ' ':
return add
elif operation == '-':
return sub
return inner_calc
in this example print(calculator(1)(' ')(7))
results in 8
. The problem is to make function which can take any number of arguments and return result when the last argument is '='. Example: print(calculator(2)(' ')('5')('-')(3)('-')(1)('='))
results in 3
. Any hints? (if it is possible i would prefer not to use any imports and global variables!)
CodePudding user response:
You can write calculator to take any input t
, and a default lambda accululator, r
-
def calculator(t, r = lambda a: a):
if isinstance(t, int):
return lambda next: \
calculator(next, lambda _: r(t))
elif t == " ":
return lambda next: \
calculator(next, lambda a: r(0) a)
elif t == "-":
return lambda next: \
calculator(next, lambda a: r(0) - a)
# else any other operation:
# ...
elif t == "=":
return r(0)
print(calculator(2)(' ')(5)('-')(3)('-')(1)('='))
2 5 - 3 - 1 =
7 - 3 - 1 =
4 - 1 =
3
This works reliably well, even when "overriding" operations -
calculator(5)(" ")("-")(3)("=") # 2
calculator(5)(" ")("-")(" ")(3)("=") # 8
However not so much when multiple numbers are provided without operations to combine them -
calculator(5)(4)(3)("=") # 5
This is a toy program for what seems like a toy assignment, however I think there is a lot to learn if you consider pocket calculator arithmetic can be a fun way to implement your first language. See this Q&A for details.
To clarify what I mean, consider this dramatically simplified version of calc
-
def calc(t, r = ()):
if t == "=":
return r
else:
return lambda next: \
calc(next, (*r, t))
print(calc(2)(' ')(5)('-')(3)('-')(1)('='))
print(calc(5)(" ")("-")(3)("="))
print(calc(5)(" ")("-")(" ")(3)("="))
print(calc(5)(4)(3)("="))
(2, ' ', 5, '-', 3, '-', 1)
(5, ' ', '-', 3)
(5, ' ', '-', ' ', 3)
(5, 4, 3)
Instead of trying to compute everything in super complex function, calc
forms an resulting expression, r
. In the final step, rather than returning the expression as output, we can tokenize and parse to compute the desired result, using your intended order of operations -
def calc(t, r = ()):
if t == "=":
return eval(parse(tokenize(r))) # <--
else:
return lambda next: \
calc(next, (*r, t))
def tokenize(t):
# ...
def parse(t):
# ...
def eval(t):
# ...
This gives you the ability to aptly handle expressions like
calc(5)(3)(" ")(1)(0)(7)("*")(2)("=")
Perhaps tokenizing as -
53 107 * 2 =
And evaluating with left-to-right order of operations -
53 107 * 2 =
160 * 2 =
320
Or evaluating with PEMDAS, for example -
53 107 * 2 =
53 214 =
267
Implementing tokenize
, parse
, and eval
is left as an exercise for the reader. If you have any questions, I am happy to assist.