1

I am struggling with this recursion problem. I want to create a calculator to basic operations in python with recursion.

ops = {"+": (lambda x,y: x+y), "-": (lambda x,y: x-y), "*": (lambda x,y: x*y)}

def calculator(expr):
   for i in expr:
       if type(i) != tuple:
           return (ops[expr[1]] (expr[0],expr[2]))
       else:
           return calculator((i))

for calculator(((1, '+', 2), '*', 3)) I expected 9 but i get (1, '+', 2, 1, '+', 2, 1, '+', 2)

Please can you help?

Pedro Pinto
  • 125
  • 6

3 Answers3

0

I'm not sure if you'll ever recurse in this…

a couple of immediate issues:

  • i will never be tuple, but it might sometimes be an instance of one: you can check with isinstance(i, tuple)

  • you're never evaluating the parameters to your operations

this will cause your code to do:

  1. calculator(((1, '+', 2), '*', 3))
  2. ops['*']((1, '+', 2), 3)
  3. (1, '+', 2) * 3

note that "multiplying" a list or tuple by n will cause it's elements to be repeated n times — which is what you're seeing

Sam Mason
  • 15,216
  • 1
  • 41
  • 60
0

You are basically writing a binary tree traversal, specifically a binary expression tree. Using a tuple is one way to represent the tree (although there are better ways, like actually implementing a binary tree).

Now, about your code. Your expression can come in two different forms: a number or a tuple. The first one is just a simple boring number. The tuple will serve to represent a more complex expression. Because it's a binary tree, the tuples will always have three elements.

The following code should work.

#ops is defined as you defined it
def calculate(expr):
    if isinstance(expr, int): # this is the terminating condition for your recursion
        return expr
    if isinstance(expr, tuple):
        return ops[expr[1]](calculate(expr[0]), calculate(expr[2]))

The code will output the final integer result. Of course, you can also use other numerical types (e.g. float). For starting out recursion in python, this is fine.

P.S.: code isn't tested, do tell if it doesn't work.

  • On quick visual inspection, it can't work as `calculate(expr)` takes one argument but the last line calls it with two: `(calculate(expr[0], expr[2])`. And the parentheses aren't balanced. My guess is you want: `(calculate(expr[0]), calculate(expr[2]))` – cdlane Dec 24 '18 at 03:49
  • Yeah, I missed that. I fixed the code in my post. Thanks. – MikeGilbert Dec 26 '18 at 14:04
0

Your evaluation logic is off -- given these simple expressions, we're really only concerned with two cases, tuple or not tuple. If it's a tuple, we apply the embedded binary operator to the recursive call of calculator() on the two arguments. If it's not a tuple, just return it as-is:

OPERATIONS = { \
    "+": (lambda x, y: x + y), \
    "-": (lambda x, y: x - y), \
    "*": (lambda x, y: x * y), \
}

def calculator(expr):
    if isinstance(expr, tuple):
        return OPERATIONS[expr[1]](calculator(expr[0]), calculator(expr[2]))

    return expr

print(calculator(((1, '+', 2), '*', 3)))

OUTPUT

> python3 test.py
9
>

My believe is, if you try to do anything more sophisticated with this simple code, you'll quickly run into problems.

cdlane
  • 40,441
  • 5
  • 32
  • 81