emacs: Symbol's function definition is void: loop
Asked Answered
S

1

8

I am testing on loading packages in emacs init.el (Emacs 24.3). I followed a blog by the author of emacs prelude to automatically load packages, and copied the code there into my init.el as in the bottom. However, I got an error message about the loop function/symbol, which says:

Symbol's function definition is void: loop

Can someone please explain how to fix the code?

I've searched around on the internet, and it seems that loop is a macro in cl-lib. My guess is that the definition for loop is missing, and I attempted to fix the problem by adding (require 'cl-lib), as shown in the code, but the error remains. There are other SO questions on similar error messages, e.g.: ELisp: cl-loop for "Symbol's value as variable is void", Symbol's function definition is void: declare-function. But the error messages are different on what's missing, and the answers mostly suggest alternative routes, such as using newer version of emacs.

-- code --

(require 'package)
(add-to-list 'package-archives
  '("melpa-stable" . "http://stable.melpa.org/packages/") t)
(package-initialize)

;;; check & load packages
(defvar prelude-packages
  '( haskell-mode )
  "A list of packages to ensure are installed at launch.")

;;(require 'cl-lib) ;debug
(defun prelude-packages-installed-p ()
  (loop for p in prelude-packages
        when (not (package-installed-p p)) do (return nil)
        finally (return t)))

(unless (prelude-packages-installed-p)
  ;; check for new packages (package versions)
  (message "%s" "Emacs Prelude is now refreshing its package database...")
  (package-refresh-contents)
  (message "%s" " done.")
  ;; install the missing packages
  (dolist (p prelude-packages)
    (when (not (package-installed-p p))
      (package-install p))))

(provide 'prelude-packages)
;;; end load packages
Shillelagh answered 15/6, 2015 at 14:14 Comment(1)
This may help: (Emacs 24.3.1): loop is an alias for cl-loop' in cl.el'. And cl-loop is a Lisp macro in `cl-macs.el'. Do C-h f loop.Fledgy
S
12

The cl-lib package was introduced in Emacs 24.3, and provides a number of Common Lisp features, all with the cl- prefix. Before that, the only way to use those features was to require the cl library, and use unprefixed names, e.g. loop instead of cl-loop. However, that was discouraged because of the possibility for name conflicts, and it's usually recommended to use the prefixed names if possible.

Since you are using Emacs 24.3, the "correct" way to fix this would be to replace loop with cl-loop and return with cl-return:

(defun prelude-packages-installed-p ()
  (cl-loop for p in prelude-packages
           when (not (package-installed-p p)) do (cl-return nil)
           finally (cl-return t)))

(You don't need (require 'cl-lib), because cl-loop and cl-return are autoloaded.)

Alternatively, you could add (require 'cl) to get access to the unprefixed names, and leave the code as it is. This will also work on earlier Emacs versions.


I can't help noticing that this function could be written more succinctly:

(defun prelude-packages-installed-p ()
  (cl-every 'package-installed-p prelude-packages))

The same issue about cl-every plus cl-lib vs every plus cl applies.

Specialism answered 15/6, 2015 at 15:23 Comment(1)
I had to require cl-lib to get cl-every to work in emacs 24.5.1Rebroadcast

© 2022 - 2024 — McMap. All rights reserved.