2

The following code seems fine semantically:

;; -*- lexical-binding: nil; -*-
(named-let f ((_ '(1)))
  (dolist (paren-1-paren _)
    (f ())))

Why does it throw an error?

(Is this a bug? If so, I will report it.)


Reported as bug#64290.

shynur
  • 4,065
  • 1
  • 3
  • 23
  • @Drew: This question *essentially* has nothing to do with \[list\]; I'm just using it as an example. You can try this: `(named-let f ((n 1)) (dotimes (i n) (f 0)))`. |||| So I removed tag\[list\]. – shynur Jun 25 '23 at 21:55
  • You're right. Thx. – Drew Jun 26 '23 at 01:31

1 Answers1

3

Refer to C-hig (cl)Function Bindings:

-- Macro: cl-labels (bindings...) forms...
The ‘cl-labels’ form is like ‘cl-flet’, except that the function bindings can be recursive. The scoping is lexical, but you can only capture functions in closures if ‘lexical-binding’ is ‘t’. *Note (elisp)Closures::, and *note (elisp)Using Lexical Binding::.

Which is relevant because your code expands to:

(funcall
 (cl-labels
     ((f
       (_)
       (dolist
           (paren-1-paren _)
         (f nil))))
   #'f)
 '(1))

And ultimately:

(funcall
 (let
     (--cl-f--)
   (setq --cl-f--
         #'(lambda
             (_)
             (let
                 ((--dolist-tail-- _)
                  paren-1-paren)
               (while --dolist-tail--
                 (setq paren-1-paren
                       (car --dolist-tail--))
                 (funcall --cl-f-- nil)
                 (setq --dolist-tail--
                       (cdr --dolist-tail--))))))
   --cl-f--)
 '(1))

In which we can see specifically where that error would occur in the absence of lexical binding.

As the recursive call seems like a standard property of named-let I suggest you raise a documentation bug to suggest that it should indicate the lexical-binding requirement (which is maybe implicitly present in the existing reference to Scheme -- but only if you know something about Scheme).

phils
  • 48,657
  • 3
  • 76
  • 115