Схема программы, не оценивающая вложенные списки?

Я пишу программу-схему, которая оценивает список с оператором в конце.

Пример: (вычислить '(1 2 +)) --> 3

У меня есть функция, работающая для основных операторов (+, -, *, /), но проблема возникает, когда у меня есть вложенный список.

Пример: (вычислить '(1 (2 3 +) *)) --> (ничего)

Я пропустил условие?

    (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)))))))))

person Disc0nnect    schedule 11.04.2017    source источник


Ответы (2)


Вы забыли рекурсивно вызвать процедуру для подвыражений. Смотрите здесь, где я для краткости переименовал его в !:

(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)))))))))

Кстати, вот как вы могли бы переписать программу более идиоматически:

(define (evaluate lis)
  (cond
    ((not (list? lis)) lis)
    ((= (length lis) 3)
     (let ((op (case (caddr lis)
                 ((+) +)
                 ((-) -)
                 ((*) *)
                 ((/) /))))
       (op (evaluate (car lis)) (evaluate (cadr lis)))))))
person Brendan Cannell    schedule 11.04.2017
comment
О, теперь я вижу проблему. Я почему-то думал, что мои утверждения работают наизнанку. Я совершенно забыл рекурсивно вызвать функцию. Я очень новичок в Scheme, поэтому интересно посмотреть, как здесь работают списки. Благодарю вас! - person Disc0nnect; 11.04.2017

У меня есть 3 указателя:

Если один из аргументов является выражением, вы его не вычисляете. Таким образом. вам также нужно запустить postfix для обоих аргументов.

Когда длина не равна 3, вы позволяете реализации выбирать, какое значение должно возвращать if. Для рэкета это #<void>. Может быть, вам стоит что-то выбрать?

Поскольку у вас есть фиксированное количество аргументов для ваших слов, скобки не нужны:

(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

Обратите внимание, что здесь аргументы фактически оцениваются автоматически. Вот как это делают конкатенирующие языки (также известные как стековые языки).

person Sylwester    schedule 11.04.2017