Is using do* without a body expression considered a bad practice in Common Lisp?

Viewed 66

I am trying to learn Common Lisp with the book Common Lisp: A gentle introduction to Symbolic Computation. In addition, I am using SBCL, Emacs, and Slime.

In chapter 11, the author presents the do* function for iteration. A little bit before, the book shows a template for the do function:

(DO ((var1 init1 [update1])
     (var2 init2 [update2])
     ...)
    (test action-1 ... action-n)
 body)

The book does not show a template for do*. Probably, because it would be identical, despite the differences between do and do*.

On exercise 11.11, the book asks:

11.11 Rewrite the following function to use DO* instead of DOLIST.

(defun find-largest (list-of-numbers)
  (let ((largest (first list-of-numbers)))
    (dolist (element (rest list-of-numbers)
                     largest)
      (when (> element largest)
        (setf largest element)))))

This is the implementation from the answer sheet:

(defun do*-find-largest-answer-sheet (list-of-numbers)
  (do* ((largest (first list-of-numbers))
        (z (rest list-of-numbers) (rest z))
        (element (first z) (first z)))
       ((null z) largest)
    (when (> element largest)
      (setf largest element))))

My implementation returns correct results but it has a different style:

(defun do*-find-largest (list-of-numbers)
  (do* ((x list-of-numbers (rest x))
        (e (first x) (first x))
        (largest (car list-of-numbers) (if (> e largest) e largest)))
       ((null (rest x)) (return largest))))

As you can see, unlike the book's answer, I do not use anything in the space usually reserved for body expressions. Also, I inserted the conditional expression inside the local variable update. I like the fact that my approach is shorter.

Would my approach be considered a bad style or bad practice in Common Lisp? Would it be acceptable?

Since "you do not know what you do not know", is there any downside on my implementation that I am not aware of?

2 Answers

Generally, it is not considered bad practice. However, you should avoid overly complex updates and end tests just just because you don't want a do(*) body.

There is nothing wrong in writing a do* loop without body. Here is an alternative version:

(defun do*-find-largest (list-of-numbers)
  (do* ((x list-of-numbers (cdr x))
        (largest (car x) (max largest (car x))))
       ((null (cdr x)) largest)))
Related