Как я могу использовать внешние переменные в Eval в схеме? - PullRequest
0 голосов
/ 02 октября 2010

Я пробую что-то в Схеме для развлечения.Я пытаюсь создать функцию Area, которая получает тип объекта, над которым она работает, а затем вызывает другую функцию в зависимости от типа объекта.Вот мой код:

(define (area object)
  (if (not (null? (eval (word 'area- (get-type object)))))
      (eval (list (word 'area- (get-type object)) 'object))
      #f
  )
)

Схема не нравится это, потому что он говорит, что объект является несвязанной переменной.Нет, я не могу убрать цитату, потому что тогда она фактически помещает туда значение, а затем Scheme жалуется, что список искажен.

Что я могу сделать, чтобы использовать значение в объекте в eval?

Примечание: Схема, по-видимому, прекрасно захватывает глобальную переменную "объект", поэтому в основном игнорируется то, что она находится внутри функции.

Некоторая информация для родственного языка находится здесь: http://docs.racket -lang.org / guide / eval.html , что, похоже, указывает на то, что в Схеме нет решения, но если вы знаете его, я бы хотел услышать его.

Ответы [ 3 ]

3 голосов
/ 02 октября 2010

Нет ни одного - и это особенность. eval выполняет оценку формы, которая была сгенерирована динамически во время выполнения. Так что, если ему нужно знать о локальных привязках, вам нужно скомпилировать (lamba (x) x) и (lambda (y) y) по-разному - потому что имя имеет значение. Но это только подсказка, существует множество проблем, связанных с реализацией такого рода функций.

Что касается вашей проблемы - даже если можно было делать то, что вы хотите, это хрупкое решение, которое зависит от имени. Помните, что в Scheme вы можете использовать функции, как и любое другое значение - поэтому вместо вызова get-type и объединения его с каким-либо символом для получения имени, сделайте ваши объекты содержащими нужную функцию (которую в этот момент лучше назвать "метод").

Что-то вроде:

(define (area object)
  ((get-area-method object) object))

Очевидно, что это означает, что нет смысла не проделывать весь путь с:

(define (area object)
  (get-area object))

что просто

(define area get-area)

Но первая может быть более типичной для обычной ОО-подобной системы, с возможностью получения методов, поэтому она может быть полезна для вас. Это направление может привести вас к:

(define (area object)
  ((get-method object 'get-area) object))
2 голосов
/ 03 октября 2010

Ракетка имеет классов и методов , и вы должны использовать ее!

(define circle%
  (class object%
    (init radius)
    (define r radius)
    (super-new)
    (define/public (area)
      (* pi r r))))

(define rectangle%
  (class object%
    (init width height)
    (define w width)
    (define h height)
    (super-new)
    (define/public (area)
      (* w h))))

(define unit-circle (new circle% [radius 1]))
(define unit-square (new rectangle% [width 1] [height 1]))

(send unit-circle area)   ; => 3.141592653589793
(send unit-square area)   ; => 1

Гораздо менее хакерский, чем отправка по имени.

0 голосов
/ 02 октября 2010

Очевидно, есть способ сделать то, что я хотел сделать в Схеме.Вот код:

(define (area object)
  ((eval (list 'identity (word 'area- (get-type object)))) object)
)

По сути, дело в следующем: поскольку eval знает только о глобальных переменных, я все еще могу использовать функцию идентификации внутри eval, чтобы вернуть значение глобальной переменной.Глобальная переменная, которая меня интересует в этом случае, - это функция, которая похожа на любую другую переменную.Затем я могу вернуть это значение и использовать его в качестве процедуры для вызова моего исходного аргумента.Это позволяет мне создать имя переменной, которую я хочу получить из глобальной области видимости, и получить и использовать процедуру, содержащуюся в этой переменной, для достижения результата, который я искал.

Вот более чистая версия:

(define (area object)
  ((get-function (word 'area- (get-type object))) object)
)

(define (get-function function)
  (eval (list 'identity function)))

Очевидно, что часть is-not-null не будет работать, потому что попытка получить идентификатор несуществующей функции вызывает ошибку несвязанной переменной.Итак, все же нужно быть осторожным, чтобы вызывать оператор для типа, который его поддерживает.

...