0

I'm trying to write a macro that can generate a set of functions that I can use to access project directories in a more efficient fashion. If you look at the following macro, you should have a good idea what I'm trying to do.

(defmacro create-project-cmd (project-name project-dir &optional subdir-list)
  (if (null subdir-list)
      `(fset (intern ,project-name) #'(lambda () (interactive) (dired ,project-dir)))
      `(dolist (dir ,subdir-list)
         (fset (intern (concat ,project-name "-" dir))
               #'(lambda () (interactive) (dired (concat ,project-dir "/" dir)))))))

The problem here is the "dir" in the last line is supposed to bond to the "dir" in dolist clause. And since there is no closure in elisp, when I call a function that is generated, it will complain dir is void.

As you can see from the code, I have faked a closure for "project-dir". I can't fake it the same way for "dir". Even though lexical-let will make it work here, I'm trying to avoid it, since it has some memory issues, and I don't want to grow a habit of using it (maybe I'm too picky here).

I do not have a good way to handle this. Anyone have any good suggestions?

sudo
  • 647
  • 2
  • 7
  • 19
  • possible duplicate of [How to overcome the lack of local variable for emacs lisp closure](http://stackoverflow.com/questions/6955544/how-to-overcome-the-lack-of-local-variable-for-emacs-lisp-closure) – phils Sep 16 '11 at 02:09

1 Answers1

2

Edit: If lexical-let is out, how about something like this:

(defmacro create-project-cmd (project-name project-dir &optional subdir-list)
  (if (null subdir-list)
      `(fset (intern ,project-name) #'(lambda () (interactive) (dired ,project-dir)))
    (let ((fsets nil))
      (dolist (dir subdir-list)
        (add-to-list
         'fsets
         `(fset (intern (concat ,project-name "-" ,dir))
                #'(lambda () (interactive) (dired (concat ,project-dir "/" ,dir))))))
      `(progn ,@fsets))))

(create-project-cmd "projfoo" "projdir" ("foo" "bar" "baz"))

(symbol-function 'projfoo-bar)
(lambda nil (interactive) (dired (concat "projdir" "/" "bar")))
Community
  • 1
  • 1
phils
  • 71,335
  • 11
  • 153
  • 198
  • Thank you for your information, but I have considered all of that. As you can see from the code, I have already faked the closure using macro for "project-dir". But for "dir", it is more difficult, since it's inside a macro, if I use another macro call it will only pass the symbol name instead of the value and I cannot get the value until run time, I have tried and failed. I'm also trying to avoid using lexical-let, since it has some memory issues needs to be result, so I don't want to grow a habit of using it (even though it will make it work here). – sudo Sep 16 '11 at 02:50
  • Yes, I was indeed assuming that you would want to use `lexical-let` there. How about this? ^^ – phils Sep 16 '11 at 03:27
  • Ahh, I was thinking something like that, but I totally forgot about the ,@ operator. Thanks a lot. :) – sudo Sep 16 '11 at 05:10
  • Ah, there it is. I knew I had another bad macro somewhere in my answers. Please note that it won't work when compiled, as macro expansion happens at compile time. I need to fix this. – phils Apr 16 '12 at 06:05