1

I am using following code modified from Solving Infix Arithmatic in LISP with definition of atom from Check if an argument is a list or an atom to have an infix arithmetic solver:

(define atom? (or/c number? symbol? boolean? string?)) 

(define (solve expression)
  (define templist '())
  (println expression)
  (if (atom? expression)
      expression
      (begin
        (set! templist (list (second expression)
                             (solve (first expression))
                             (solve (third expression))  ))
        (println templist)
        (eval templist) ) ) )

(solve '(3 + 2))

The output is as follows:

'(3 + 2)
3
2
'(+ 3 2)
+: unbound identifier;
 also, no #%app syntax transformer is bound in: +

Hence, the templist is created all right (+ 3 2) but there is error at eval level. Why is '+' seen as an 'unbound identifier'? The eval function otherwise works well on the command line in DrRacket:

> (eval '(+ 3 2))
5

Where is the problem and how can it be solved? Thanks.

Community
  • 1
  • 1
rnso
  • 23,686
  • 25
  • 112
  • 234

1 Answers1

3

Have you not been learning from the answers to your previous questions? Do not use set!, it is not good Scheme/Racket style. It’s especially egregious here because it is doing absolutely nothing at all; take it out and use let (or local, or block with internal definitions, if you’d prefer).

That aside, eval is equally evil, and you don’t need it here. Functions are first class; create a mapping between symbols and functions, then just use the mapping to fetch the relevant function to invoke.

(define (operator->procedure op)
  (case op
    [(+) +]
    [(-) -]
    [(*) *]
    [(/) /]
    [else (error 'operator->procedure "unknown operator ~v" op)]))

(define (solve expression)
  (if (atom? expression)
      expression
      ((operator->procedure (second expression))
       (solve (first expression))
       (solve (third expression)))))

To be even clearer, you could use Racket’s pattern-matching form, match:

(define (solve expression)
  (match expression
    [(? atom) expression]
    [(list a op b)
     ((operator->procedure op) (solve a) (solve b))]))
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
Alexis King
  • 43,109
  • 15
  • 131
  • 205
  • I had used set! and templist only to debug the code, otherwise only "eval (list (second expression)... " is needed. Why is set! there in language if it not to be used at all? Thanks for a well explained answer. – rnso Aug 01 '16 at 06:07
  • 1
    @rnso Perhaps, but your `set!` isn’t do anything at all there. Even if your original code, you could have just used a local binding. I would say that, until you’re extremely comfortable with Scheme/Racket, *never* use `set!`. Not even for debugging. Pretend it doesn’t exist. – Alexis King Aug 01 '16 at 06:09
  • @rnso `set!` is useful for implementing some low-level constructs in Scheme, but it’s not something that’s useful in most user code. Usually you can avoid mutation altogether, and if you really, really want something to be mutable, you can use boxes instead (but I would avoid those, too, unless you’re 100% sure you need them). – Alexis King Aug 01 '16 at 06:11
  • Thanks for the explanation. Above code works well for expressions like (3 + 2) but not for (3 + 2 + 1) since only first 3 elements are evaluated. Any easy solution for this? – rnso Aug 01 '16 at 06:20
  • @rnso That’s a separate question, so I won’t answer it here, but I think it’s something you might be able to figure out for yourself. Try it, and if you get really stuck, ask another question. – Alexis King Aug 01 '16 at 06:21
  • this is a useless answer that maybe just happens to help with what the original question was actually trying to do, but it doesn't address the question as stated. – David Pasquinelli Jun 29 '23 at 22:03