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))))

Created: NaN

Last updated: 23-01-2025 [00:04]


For attribution, please cite this page as:

Charters, T., "Revenge of the nerds": https://nexp.pt/rev_nerds.html (23-01-2025 [00:04])


(cc-by-sa) Tiago Charters - tiagocharters@nexp.pt