Disc0nnect
Disc0nnect

Reputation: 3

Scheme program not evaluating nested lists?

I'm writing a scheme program that evaluates a list with the operator on the end.

Example: (evaluate '(1 2 +)) --> 3

I have the function working for basic operators (+, -, *, /) but the issue comes in when I have a nested list.

Example: (evaluate '(1 (2 3 +) *)) --> (nothing)

Am I missing a condition?

    (define (evaluate lis)
     (cond
      ((not (list? lis))
        lis)
      ((list? lis)
        (if (equal? (length lis) 3)
          (cond
            ((equal? (cddr lis) '(+))
             (+ (car lis) (car (cdr lis))))
            ((equal? (cddr lis) '(-))
             (- (car lis) (car (cdr lis))))
            ((equal? (cddr lis) '(*))
             (* (car lis) (car (cdr lis))))
            ((equal? (cddr lis) '(/))
             (/ (car lis) (car (cdr lis)))))))))

Upvotes: 0

Views: 327

Answers (2)

Sylwester
Sylwester

Reputation: 48745

I have 3 pointers:

If one of the arguments are an expression you are not evaluating it. Thus. you need to run postfix on both arguments as well.

When the length is not 3 you let the implementation choose what value the if should return. For racket its #<void>. Perhaps you should choose something?

Since you have a fixed number of arguments for your words there is no need for parentheses:

(define (peval exprs)
  (define primitives `((+ . ,+) (- . ,-) (* . ,*) (/ . ,/)))
  (foldl (lambda (operator operands)
           (let ((aproc (assq operator primitives)))
             (if aproc
                 (cons ((cdr aproc) (cadr operands) (car operands))
                       (cddr operands))
                 (cons operator operands))))
         '()
         exprs))

(peval '(2 3 4 + *)) ; (2 (3 4 +) *) == 14

Notice that here the arguments actually gets evaluates automatically. This is how the concatenating languages (aka stack languages) do it.

Upvotes: 1

Brendan Cannell
Brendan Cannell

Reputation: 679

You forgot to recursively call the procedure on the sub-expressions. See here, where I've renamed it ! for brevity:

(define (! lis)
  (cond
    ((not (list? lis))
     lis)
    ((list? lis)
     (if (equal? (length lis) 3)
       (cond
         ((equal? (cddr lis) '(+))
          (+ (! (car lis)) (! (cadr lis))))
         ((equal? (cddr lis) '(-))
          (- (! (car lis)) (! (cadr lis))))
         ((equal? (cddr lis) '(*))
          (* (! (car lis)) (! (cadr lis))))
         ((equal? (cddr lis) '(/))
          (/ (! (car lis)) (! (cadr lis)))))))))

Incidentally, here's how you might rewrite the program more idiomatically:

(define (evaluate lis)
  (cond
    ((not (list? lis)) lis)
    ((= (length lis) 3)
     (let ((op (case (caddr lis)
                 ((+) +)
                 ((-) -)
                 ((*) *)
                 ((/) /))))
       (op (evaluate (car lis)) (evaluate (cadr lis)))))))

Upvotes: 0

Related Questions