Home > Blockchain >  Recursive calculator with adding and substracting
Recursive calculator with adding and substracting

Time:11-21

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.

  • Related