Revenge of the nerds
Em 2002 Paul Graham escreveu um artigo intitulado "Revenge of the Nerds" que, entre outras coisas, fala das vantagens do uso de Lisp e o que o torna diferente das outras linguagens de programação. O que me levou até este artigo foi aquilo de que se trata no apêndice, i.e., sobre o poder de uma linguagem de programação.
As an illustration of what I mean about the relative power of programming languages, consider the following problem. We want to write a function that generates accumulators— a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. (That's incremented by, not plus. An accumulator has to accumulate.)
Em Common Lisp a função que faz isto é dada por
(defun foo (n) (lambda (i) (incf n i)))Para ver como funciona põe-se
> (setq a (foo 3))
#<FUNCTION :LAMBDA (I) (INCF N I)>
> (funcall a 1)
4
Fui ver então se a mesma função foo
, definida anteriormente, funciona em Emacs
Lisp. Depois de (funcall a 1)
o resultado é este:
Debugger entered--Lisp error: (void-variable n) (+ n i) (setq n (+ n i)) (incf n i) (lambda (i) (incf n i))(1) funcall((lambda (i) (incf n i)) 1) eval((funcall a 1)) eval-last-sexp-1(nil) eval-last-sexp(nil) call-interactively(eval-last-sexp
Aparentemente a variável n
é considerada como local na definição de foo
, mas
isto não faz sentido nenhum. É um
bug acidental ou propositado do dialecto de Lisp que corre no Emacs?
Email enviado para a mailing list do Emacs. Novidades aqui, mais tarde.
Já recebi a resposta da mailing list. Aqui está ela:
Should not the function foo in Common Lisp work with Emacs Lisp?
(defun foo (n) (lambda (i) (incf n i)))
No, that won't work because emacs has no lexical scoping and that code is a closure. See the elisp manual:
,----[ (info "(elisp)Extent") ] | To illustrate this, the function below, `make-add', returns a | function that purports to add N to its own argument M. This would work | in Common Lisp, but it does not do the job in Emacs Lisp, because after | the call to `make-add' exits, the variable `n' is no longer bound to | the actual argument 2. | | (defun make-add (n) | (function (lambda (m) (+ n m)))) ; Return a function. | => make-add | (fset 'add2 (make-add 2)) ; Define function `add2' | ; with `(make-add 2)'. | => (lambda (m) (+ n m)) | (add2 4) ; Try to add 2 to 4. | error--> Symbol's value as variable is void: n | | Some Lisp dialects have "closures," objects that are like functions | but record additional variable bindings. Emacs Lisp does not have | closures. `----
Mais uma resposta da mailing list:
Emacs Lisp has dynamic scoping, not lexical scoping. If you want to emulate lexical scoping, (require 'cl-macs) and use lexical-let:
(defun foo (n) (lexical-let ((lexn n)) (lambda (i) (incf lexn n))))Palavras chave/keywords: Lisp, Emacs, Paul Graham, bug
Criado/Created: NaN
Última actualização/Last updated: 10-10-2022 [14:26]
(c) Tiago Charters de Azevedo