10

Is it possible to automatically verify that a piece of lisp code does not create any new global variables? Turn on lexical-binding: ;;; foo.el --- just frobnicating some foo -*- lexical-binding: t -*- (setq foo-bar nil) (defun foo-bar () (let (x) (setq y nil))) ;;; foo.el ends here and then the byte-compiler will do the work for you: emacs -Q -...


9

The byte-compiler's way to decide whether a function will be defined or not is very "naive" and gets fooled even in your "obvious" case. But you can write it in a way that lets the compiler understand what happens: (defalias 'increase-count (let ((count 0)) (lambda () (interactive) (setq count (1+ count)) (message "Count is: %d" ...


8

Without cl-lib: ;; -*- lexical-binding: t; -*- (defun nats () (letrec ((inner (lambda (n) (cons n (lambda () (funcall inner (1+ n))))))) (funcall inner 0))) (let* ((stream (nats)) (i (car stream))) (while (< i 10) (message "Got %i" i) (setq stream (funcall (cdr stream)) i (car stream)))) See also https://github.com/...


7

Elisp AFAIK the only two reliable ways for using lexical binding in Elisp files are: Setting the buffer-local variable lexical-binding as file-local variable at the beginning of the Elisp file with ;;; -*- lexical-binding: t; -*- Using eval with non-nil LEXICAL argument. (LEXICAL can be t or the lexical environment to be used) Motivation for that behavior ...


7

You asked: Will be useful to write/build literal closures? Should it be a good practice? any example? Why the closure is not a real type instead of cons? All three questions are answered with the following quote of the elisp manual: However, the fact that the internal structure of a closure is exposed to the rest of the Lisp world is ...


6

Quoth the docstring of special-variable-p: special-variable-p is a built-in function in `src/eval.c'. (special-variable-p SYMBOL) Probably introduced at or before Emacs version 24.1. Return non-nil if SYMBOL's global binding has been declared special. A special variable is one that will be bound dynamically, even in a context where binding is lexical by ...


6

To suppress the byte-compiler warning, try adding this before your code, starting in column 0 (leftmost): (declare-function increase-count "your-file-name.el") C-h f declare-function tells you: declare-function is a Lisp macro in subr.el. (declare-function FN FILE &optional ARGLIST FILEONLY) Tell the byte-compiler that function FN is ...


5

This code shows an elisp function (third example) using lexical-let This is the (renamed) third example in the linked page: (eval-when-compile (require 'cl)) ;; for `lexical-let' macro (defun compose-cl (f g) (lexical-let ((f f) (g g)) (lambda (x) (funcall f (funcall g x))))) which is now passe as I understand. Yes. How ...


5

Here's a trivial example: ;; -*- lexical-binding: t; -*- (defun foo () x) (let ((x 'y)) (foo)) Save that file and use M-x load-file to load it, and you will get an error: let: Symbol’s value as variable is void: x On account of lexical variable x not being visible within function foo. Under dynamic binding, foo would see the value y. ... being ...


4

Turn on the header :lexical, e.g., #+begin_src elisp :lexical t :results pp (lambda ()) #+end_src #+RESULTS: : (closure : (t) : nil) You can also use #+PROPERTY: header-args:elisp :lexical t to turn it on for the whole org file. Or change org-babel-default-header-args:emacs-lisp to turn it on globally. (setq lexical-binding t) in the code does not work ...


4

TL;DR M-: (setq lexical-binding t) Details A precondition for iterators in Emacs to work is that the variable binding is set to lexical binding for the respective file or buffer. Evaluate (setq lexical-binding t) to turn on lexical binding. The assertion can be interpreted to make sure that lexical binding is set when using iterators. Find more ...


3

Your example is likely not representative of the actual code you're using, but a good solution might be to create the closure in the macro and return the closure, instead of returning code which may or may not turn into a closure depending on lexical-binding: (defmacro repro () (let* ((kmap-sym (gensym "kmap-"))) `(let ((,kmap-sym (make-sparse-keymap))...


3

I believe placing the definition in question within eval-and-compile would also superficially achieve the same result as in Stefan's correct answer: (eval-and-compile (let ((count 0)) (defun increase-count () (interactive) (setq count (1+ count)) (message "Count is: %d" count)))) I am, however, barely familiar with the subtleties of ...


2

Correct, it's set on a per-file/buffer basis. I could not do (setq lexical-binding t) in my init file and have it apply to all subsequent buffers, right? Indeed not, and nor would you want to do that. Libraries may behave differently with lexical binding enabled, and for the vast majority of the history of Emacs that wasn't an option, so no one was ...


2

There is an ugly workaround using eval with the optional argument LEXICAL set to t. (defmacro repro () (let ((kmap-sym (gensym "kmap-"))) `(eval '(let ((,kmap-sym (make-sparse-keymap))) (define-key ,kmap-sym "a" (lambda () (interactive) (message "kmap is %s" ,kmap-sym))) ,kmap-sym) t))) It is ugly since the ...


2

Your problem is that the let-bound symbol the-fn is not yet available when you define the lambda. Use letrec instead of let*. It first binds all variables and afterwards sets them. Example: (defun my-test () (letrec ((the-fn (lambda (recursive) (message "Calling the-fn with arg %s." recursive) (when ...


1

In a private email, Christopher Wellons answered my question. The problem is that server-process is a special variable defined in server.el. Special variables are always dynamically bound. As a result, the filter closure doesn't close over the server-process variable. When the filter closure is evaluated, the server-process variable's value is the one from ...


1

The lexical-binding is a setting that by-and-large operates at compile-time and not at run-time (more specifically, it applies to code that's being manipulated rather than code that's being executed). So at run-time, better not pay too much attention to it (its value will depend on the buffer that happens to be current when the code is executed) unless you'...


1

Not very sure if the result meets your expectation. (defun foo (keymap) `(lambda () (interactive) (message "kmap is %s" ',keymap))) (defmacro repro () (let ((kmap-sym (gensym "kmap-"))) `(let ((,kmap-sym (make-sparse-keymap))) (define-key ,kmap-sym "a" (foo ,kmap-sym)) ,kmap-sym))) (setq lexical-binding nil) ;; => nil (...


Only top voted, non community-wiki answers of a minimum length are eligible