help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [External] : Re: Testing whether a list contains at least one non-ni


From: Stefan Monnier
Subject: Re: [External] : Re: Testing whether a list contains at least one non-nil element
Date: Fri, 28 Oct 2022 09:09:12 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux)

Michael Heerdegen [2022-10-28 08:20:45] wrote:
> <tomas@tuxteam.de> writes:
>> If you are doing it "by hand", why not indulge in Lisp's
>> "classic elegance", like so:
>>
>>   (defun has-non-nil (lst)
>>     (cond
>>      ((null lst) nil)
>>      ((consp lst) (or (not (null (car lst))) (has-non-nil (cdr lst))))
>>      (t (error "Not a proper list! You cheater!"))))
>
> You don't want to implement such functions in Emacs with recursion
> because you'll easily hit `max-lisp-eval-depth' when they are called.

Indeed (and it's significantly slower than the corresponding loop
without function calls).

> Sorry to tell you, but a loop is the preferable way in Elisp.

Luckily, since Emacs-28 you can have your cake and eat it too:

    (defun has-non-nil (lst)
      (named-let loop ((lst lst))
        (cond
         ((null lst) nil)
         ((consp lst) (or (not (null (car lst))) (loop (cdr lst))))
         (t (error "Not a proper list! You cheater!")))))

Admittedly, here the `named-let` construct gives you only the
elimination of tail-recursion, but in many other circumstances it
also leads to quite elegant code.


        Stefan


PS: For the curious, here's what the above `named-let` expands to:

(defalias 'has-non-nil
  #'(lambda (lst)
      (let ((lst lst))
        (let (retval)
          (while
            (let ((lst lst))
              (cond
               ((null lst) nil)
               ((consp lst) (let ((val (not (null (car lst)))))
                              (if val (progn (setq retval val) nil)
                                (progn (setq lst (cdr lst)) :recurse))))
               (t (progn (setq retval (error "Not a proper list! You cheater!"))
                         nil)))))
          retval))))




reply via email to

[Prev in Thread] Current Thread [Next in Thread]