eval с использованием пространства имен текущей функции - PullRequest
2 голосов
/ 15 февраля 2011

Следующая функция ракетки выдает ошибку:

reference to undefined identifier: val

Это потому, что функция eval смотрит на глобальное пространство имен, а не на пространство имен локальной функции. Как заставить eval использовать пространство имен локальной функции?

(define some-eval!
  (lambda (val row col)
    (eval (list 'define 'ttboard '(list-builder val row col))) (current-namespace) ))

Ответы [ 4 ]

3 голосов
/ 15 февраля 2011

Ваш вопрос относится к Ракетке. В общем, разные реализации Scheme имеют разные подходы к этой проблеме, но почти во всех случаях вы не получите eval для обработки локальных привязок, как вы пытаетесь это сделать. Но, что касается случая с Racket, вы должны прочитать раздел оценки *1003* в руководстве по Racket - он объясняет, почему вещи не работают так, как вы этого хотите, и показывает, как заставить работать модуль модуля. .

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

(define (foo f) (let ([x 1]) (f 'x)))
(foo eval)

В этом случае компилятор не сможет сказать, что foo когда-либо будет вызываться с eval.

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

function foo(x) { alert("x = " + eval("x")); }

на самом деле будет работать - но для физического присутствия в теле функции требуется eval. Если этого не сделать, то все может сломаться. Например, этот код:

function foo(x,f) { alert("x = " + f("x")); }
foo(123,eval);

работает для меня в Fx, но не работает в Chrome, говоря, что x is not defined. И если этого недостаточно, чтобы продемонстрировать беспорядок, подумайте:

function foo(x,f) { alert("x = " + f("x")); }
var x = 456;
foo(123,eval);

показывает 456 в Chrome и в Fx.

1 голос
/ 15 февраля 2011

В общем, нет доступа к лексической среде с eval, как отмечает Эли.Тем не менее, я считаю, что этот обходной путь будет делать то, что вы хотите:

#lang racket/load

(define some-eval!
  (lambda (val row col)
    (namespace-set-variable-value! 'val val)
    (namespace-set-variable-value! 'row row)
    (namespace-set-variable-value! 'col col)
    (eval (list 'define 'ttboard '(list-builder val row col)) 
          (current-namespace))))
(define list-builder list)
(some-eval! 1 2 3)
(display ttboard)
1 голос
/ 15 февраля 2011

Вы можете определить ttboard заранее, а затем set! it:

(define ttboard #f)
(define create-board
  (lambda (val row col)
    (set! ttboard (list-builder val row col))))

Таким образом, вы можете четко сказать, что ttboard является глобальной переменной, а не скрывает ее определениев предложении eval'd.

1 голос
/ 15 февраля 2011

Я думаю, что для того, что вы хотите сделать, может быть достаточно установить значения val, row и col во время составления выражения, вместо того, чтобы интерпретатор захватывал значения val и соавт. в прежнее время (невозможно в Racket).

(define some-eval!
  (lambda (val row col)
    (eval (list 'define 'ttboard `(list-builder ,val ,row ,col)))
          (current-namespace)))

Обратите внимание, что почти наверняка есть более хороший и чистый способ выполнить то, что вы пытаетесь сделать без eval, если, конечно, вы не делаете это, чтобы попрактиковаться в использовании eval.

...