git » homepage.git » master » tree

[master] / md / Lisp / CommonLispIteration.md

Common Lisp iteration

Created Monday 23 November 2020

Each of the following definitions of a factorial function demonstrate a way to iterate in Common Lisp, with brief notes. I hope that by demonstrating many different ways that the same thing can be written, you can develop a sense for the character of the constructs afforded by the language, and of the variety of possible styles. Common Lisp is famously syntactically extensible via macros, so keep in mind that my examples are by no means the only ways to iterate.

For further reading on the iteration and control structures of Common Lisp, I heartily recommend:

Note: several of the examples return nonsensical results for negative inputs. The addition of (assert (not (minusp n))or similar is a good idea, but I have omitted it here for clarity.

DOTIMES

(defun factorial-dotimes (n &aux (prod 1))
  (dotimes (i n prod)
    (setq prod (* prod (1+ i)))))

DO

(defun factorial-do (n)
  (do ((i 1 (1+ i))
       (prod 1 (* prod i)))
      ((> i n) prod)))

LOOP

(defun factorial-loop (n)
  (loop
     for i from 1 to n
     for prod = 1 then (* prod i)
     finally (return prod)))

The preceding example demonstrates the "extended" form of LOOP. There's also "simple" form:

(defun factorial-simple-loop (n &aux (i 0) (prod 1))
  (loop
    (when (eql i n)
      (return prod))
    (setq prod (* prod (incf i)))))

Recursion

(defun factorial-recursive (n)
  (if (zerop n)
      1
      (* n (factorial-recursive (1- n)))))

PROG

(defun factorial-prog (n)
  (prog ((i 0) (prod 1))
   begin
   (when (eql i n)
     (return prod))
   (setq prod (* prod (incf i)))
   (go begin)))

TAGBODY

(defun factorial-tagbody (n &aux (i 0) (prod 1))
  (tagbody
     begin
     (when (eql i n)
       (return-from factorial-tagbody prod))
     (setq prod (* prod (incf i)))
     (go begin)))