Проблемы с оценкой выражений из пользовательского ввода - PullRequest
4 голосов
/ 19 февраля 2012

Я пытаюсь сделать рекурсивное определение, которое читает и выполняет пользовательские выражения, такие как (3 + 5). Все работает, кроме одной проблемы с арифметическим символом.

Мне удалось воспроизвести ошибку в более простом примере:

(define v '(1 + 3))

((cadr v) 2 4)

(cadr v) является символом +, но по какой-то причине процедура не может быть выполнена с двумя последующими аргументами. Я что-то упустил?

Ответы [ 4 ]

3 голосов
/ 19 февраля 2012

Я думаю, это потому, что

(cadr v)

возвращает '+ не + (литерал + не + функция).

Вам необходимо оценить его перед применением к аргументам.

Это должно работать:

((eval (cadr v)) 2 4)
 ^evaluates the '+ to +

редактировать Это работало в ракетке в интерактивном режиме.

Я не совсем уверен, в чем разница, но заставил его работать в режиме r5rs в ракетке (скрипт):

#lang r5rs

;required by r5rs
(define user-initial-environment (scheme-report-environment 5))

(define v '(1 + 2))

;eval expects a quoted expression
;(it seems that if it's a function it has to have arguments too)
;and evaluation environment.
((eval (cadr v)  user-initial-environment) 2 4)
1 голос
/ 20 февраля 2012

Как уже отмечали другие, проблема в том, что созданный вами список содержит символ плюс, а не функцию плюс.

По сути, это та же самая причина, по которой '(a b) возвращает список из двух символов, а не сигнализирует об ошибке несвязанного идентификатора; в кавычке начинается термин на «языке данных», где юридические идентификаторы интерпретируются как символы, а не как переменные ссылки.

Вопрос, конечно, в том, что вы должны с этим делать. Некоторые здесь предложили использовать «eval»; это, вероятно, плохая идея, по причинам, которые, как мне кажется, Мэттью Флэтт изящно фиксирует в своем блоге на тему .

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

#lang racket

;; a mapping from symbols to operators
(define operator-hash
  (hash '+ +
        '- -
        '* *))
;; ... and whatever other operators you want.

;; example of using it:
(hash-ref operator-hash '+) ;; ==> +
0 голосов
/ 20 февраля 2012

Вы можете сделать это с помощью eval в Guile:

(define (infix-eval v)
   (eval (list (cadr v)(car v)(caddr v))
         (interaction-environment)))

> (infix-eval '(1 + 2))
3

Вместо использования interaction-environment вы можете предоставить другую среду для оценки, где вы также можете определить некоторые другие символы, не найденныев стандартной схеме, чтобы выражения типа (7 % 3) и (2 ^ 6) также работали.

0 голосов
/ 19 февраля 2012

Попробуйте это:

(define v '(1 + 3))

(let ((operator (eval (cadr v)))
      (operand1 (car v))
      (operand2 (caddr v)))
  (apply operator (list operand1 operand2)))
...