Pergunta

Eu tenho uma s-expressão ligado a uma variável Lisp comum:

(defvar x '(+ a 2))

Agora eu quero criar uma função que, quando chamado, avalia a expressão no escopo em que foi definido. Eu tentei isso:

(let ((a 4))
  (lambda () (eval x)))

e

(let ((a 4))
  (eval `(lambda () ,x)))

Mas ambos criar um problema: EVAL irá avaliar o código no nível superior, então não posso variáveis ??de captura contida na expressão. Note que eu não posso colocar o formulário LET na EVAL. Existe alguma solução?

EDIT: Então, se não houver solução para o problema EVAL, como mais pode ser feito

EDIT: Houve uma pergunta sobre o que exatamente eu estou tento fazer. Estou escrevendo um compilador. Eu quero aceitar uma expressão s com variáveis ??fechadas no ambiente lexical onde a expressão é definida. Com efeito, pode ser melhor para escrevê-lo como uma macro.

Foi útil?

Solução

Você precisa criar código que tem as ligações necessárias. Enrole um LET em torno de seu código e vincular cada variável que deseja disponibilizar no seu código:

(defvar *x* '(+ a 2))

(let ((a 4))
  (eval `(let ((a ,a))
           ,*x*)))

Outras dicas

implementos clisp uma extensão para avaliar um formulário no ambiente lexical. A partir do fato de que é uma extensão, eu suspeito que você não pode fazer isso de uma forma compatível com o padrão.

(ext:eval-env x (ext:the-environment))

http://clisp.cons.org/impnotes.html#eval- environ .

O que é o problema real que você quer resolver? Muito provavelmente, você está tentando resolvê-lo da maneira errada. ligações lexicais são para coisas que aparecem lexically no seu âmbito, não para coisas aleatórias que você começa a partir do exterior.

Talvez você queira um fechamento dinâmico? Tal coisa não existe em Lisp comum, embora não em alguns dialetos Lisp (como Pico Lisp, tanto quanto eu entendo).

Note que você pode fazer o seguinte, que é semelhante:

(defvar *a*)
(defvar *x* '(+ *a* 2))  ;'

(let ((a 10))
  ;; ...
  (let ((*a* a))
    (eval *x*)))

Eu aconselho você a pensar muito sobre se você realmente quer isso, porém.

Em Lisp comum você pode definir * evalhook * Qual permite que você passe um ambiente para (eval ...). *evalhook* é independente de plataforma.

É possível usar compilar para compilar a expressão em função e, em seguida, usar PROGV para funcall a função compilado no ambiente onde as variáveis ??são definidas dinamicamente. Ou, melhor, use compilação para compilar a expressão em função que aceita variáveis.

Compilar aceita a definição da função como uma lista e transforma-lo em função. Em caso de SBCL, esta função é compilado em código de máquina e executar com eficiência.

A primeira opção (usando compilação e progv):

(defvar *fn* (compile nil '(lambda () (+ a 2)))
(progv '(a) '(4) (funcall *fn*))
=>
6

Segunda opção:

(defvar *fn* (compile nil '(lambda (a) (+ a 2))))
(funcall *fn* 4)
=>
6
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top