1

I want to define a list of accumulators with Emacs Lisp and write the following code, but I got a error saying that initV is a void variable. It seems initV is not evaluated in the function define-accum. Where is I make a mistake? (I just want to know why although I know there is other ways to reach my target.)

(defun define-accum (name initV)
  (defalias name (lambda (v) (+ v initV))))

(setq accums '((myadd1 . 1)
               (myadd2 . 2)))

(dolist (a accums)
  (define-accum (car a) (cdr a)))

(message "result = %d" (+ (myadd1 1) (myadd2 1)))

3 Answers 3

3

You need to use backquotes properly. This would work for you, for instance:

(defun define-accum (name initV)
  (defalias name `(lambda (v) (+ v ,initV))))

See here for an explanation

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I know the usage of backquotes but I still don't understand why there should be quoting.
The problem is that lambda is self-quoting. Therefore, initV stands literally in the alias. It is undefined at the evaluation of the alias.
2

Apart from using backquotes, you can activate lexical binding (if you're using Emacs 24 or newer). For example, if I put your code in a .el file and put this on the first line:

;; -*- lexical-binding: t -*-

then I get the output:

result = 5

This works because the lambda function in define-accum will reference the initV in the environment where it's being defined (thus picking the variable in the argument list), and create a closure over this variable. With dynamic binding (the default), the function would look for initV in the environment where it's being called.

Comments

1

To add a little to what others have said -

  1. If the variable (initV) is never actually used as a variable, so that in fact its value at the time the accumulator is defined is all that is needed, then there is no need for the lexical closure that encapsulates that variable and its value. In that case, the approach described by @juanleon is sufficient: it uses only the value at definition time - the variable does not exist when the function is invoked (as you discovered).

  2. On the other hand, the lexical-closure approach lets the function be byte-compiled. In the backquote approach, the function is simply represented at runtime by a list that represents a lambda form. If the lambda form represents costly code then it can make sense to use the lexical-closure approach, even though (in this case) the variable is not really needed (as a variable).

  3. But you can always explicitly byte-compile the function (e.g. ##NAME## in your define-accum. That will take care of the inefficiency mentioned in #2, above.

1 Comment

Note that closures don't like "variables" any more than backquoted lambdas. The only difference is that the byte-compiler will take care of rewriting the code for you if needed (e.g. it will turn (let ((a 1)) ... (setq a ..) ... a ...) into (let ((a (list 1))) ... (setcar a ..) ... (car a) ...)).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.