问题
I want to make a timer, like this one:
(defun dumb (y)
(defun P () (print y))
(run-with-timer 0 5 'P))
(dumb 5)
Then Emacs gives me this error:
Error running timer `P': (void-variable y)
I guess the problem is that in the (defun P () (print y))
line, the variable y
is not evaluated, so when I run (dumb 5)
, the function P
tries to print y
, which is undefined, instead of a literal 5
. But I don't know how to solve it. Any idea?
回答1:
First, defun
is for defining functions in the global scope. You only need to build an anonymous function instead, with a lambda form.
Second, y
is only bound to a value while dumb
is being executed (dynamic extent). Registering the function with run-with-timer
is asynchronous and exits immediately. When your callback is called, y
is not bound anymore.
You can activate lexical binding in you current buffer with a file-local variable:
;;; -*- lexical-binding: t -*-
(defun dumb (y)
(run-with-timer 0 5 (lambda () (print y))))
Alternatively, when lexical-binding
is nil
, you can "build" the lambda form with the currently bound value of y
injected in it:
(defun dumb (y)
(run-with-timer 0 5 `(lambda () (print ,y))))
回答2:
Another way to solve this is to pass the extra argument to run-with-timer
:
(defun dumb (y)
(run-with-timer 0 5 'print y))
run-with-timer
accepts any number of arguments after the function to call, and those arguments will be passed along when the timer fires.
来源:https://stackoverflow.com/questions/33382928/emacs-lisp-nested-function-void-variable-error