(lispkit iterate)

Library (lispkit iterate) defines syntactical forms supporting frequently used iteration patterns. Some of the special forms were inspired by Common Lisp.


dotimes iterates variable var over the integer range [0, count[, executing body for every iteration.

dotimes first evaluates count, which has to evaluate to a fixnum. If count evaluates to zero or a negative number, body ... is not executed. dotimes then executes body ... once for each integer from 0 up to, but not including, the value of count, with var bound to each integer. Then, result is evaluated and its value is returned as the value of the dotimes form. If result is not provided, no value is being returned.

(let ((res 0))
  (dotimes (i 10 res)
    (set! res (+ res i))))  ⟹  45

dolist iterates variable var over the elements of list lst, executing body ... for every iteration.

dolist first evaluates lst, which has to evaluate to a list. It then executes body ... once for each element in the list, with var bound to the current element of the list. Then, result is evaluated and its value is returned as the value of the dolist form. If result is not provided, no value is being returned.

(let ((res ""))
  (dolist (x '("a" "b" "c") res)
    (set! res (string-append res x))))  ⟹  "abc"

loop iterates infinitely, executing body ... in each iteration. break is a variable bound to an exit function which can be used to leave the loop form. break receives one argument which is the result of the loop form.

(let ((i 1))
  (loop break
    (if (> i 100)
        (break i)
        (set! i (* i 2)))))  ⟹  128

while iterates as long as condition evaluates to a value other than #f, executing body ... in each iteration. unless can be used to bind an exit funtion to variable break so that it is possible to leave the loop by calling thunk break. while forms never return a result.

(let ((i 0)(sum 0))
  (while (< sum 100) unless exit
    (if (> i 10) (exit))
    (set! sum (+ sum i))
    (set! i (fx1+ i)))
  (cons i sum))  ⟹  (11 . 55)

This form of for iterates through all the fixnums from lo to hi (both inclusive), executing body ... in each iteration. If step s is provided, s is used as the increment of variable var which iterates through the elements of the given range.

When this for form is being executed, first lo and hi are evaluated. Both have to evaluate to a fixnum. Then, body ... is executed once for each integer in the given range, with var bound to the current integer. The form returns no result.

(let ((res '()))
  (for x from 1 to 16 step 2
    (set! res (cons x res)))
  res)  ⟹  (15 13 11 9 7 5 3 1)

This form of for iterates through all the elements of a list, executing body ... in each iteration. The list is either explicitly given via lst or its elements are enumerated in the form (x ...). If a where predicate is provided, the it acts as a filter on the elements through which variable var is iterated.

When this for form is being executed, first lst or (x ...) is evaluated. Then, body ... is executed once for each element in the list, with var bound to the current element of the list. The form returns no result.

(let ((res '()))
  (for x in (iota 16) where (odd? x)
    (set! res (cons x res)))
  res)  ⟹  (15 13 11 9 7 5 3 1)

exit-with is not an iteration construct by itself. It is often used in combination with iteration constructs to declare an exit function for leaving statements body .... break is a variable which gets bound to the exit function in the scope of statements body .... exit-with either returns the result of the last statement of body ... or it returns the value passed to break in case the exit function gets called.

(exit-with break
  (display "hello")
  (break #f)
  (display "world"))  ⟹  #f  ; printing "hello"

Last updated