Making a circular list

How would you go about writing a function that converts a given list into a circular one? Obviously the last cons cell of the list must be made to point back to the first cons (conveniently ignoring some special cases like empty and improper lists).

(DEFUN CIRCULARIZE (LIST)
  (RPLACD (LAST LIST) (FIRST LIST))
  LIST)

That doesn’t quite cut it as this test expression shows:

;; Expecting #1=(#\a #\e #\i #\o #\u . #1#)
(LET ((*PRINT-CIRCLE* T))
  (WRITE (CIRCULARIZE (COERCE "aeiou" 'LIST))))

=> (#\a #\e #\i #\o #\u . #\a)
Filed under  //   conses  

Variable name for a function

For a change, here’s something that actually does what it’s supposed to, to wit, an anonymous function that computes the median of a list of numbers. The details of this function are unimportant, so for the main point of this article see the next paragraph.

(LAMBDA (NUMBERS)
  (LET* ((SORTED (SORT (COPY-SEQ NUMBERS) #'<))
         (SIZE (LENGTH SORTED))
         (MIDDLE-NUMBERS (NTHCDR (FLOOR (1- SIZE) 2)
                                 SORTED)))
    (IF (ODDP SIZE)
        (FIRST MIDDLE-NUMBERS)
        (/ (+ (FIRST MIDDLE-NUMBERS) (SECOND MIDDLE-NUMBERS))
           2))))

The following expression binds the local variable name (not function name!) MEDIAN to the function. As a result, all but one of the calls to MEDIAN are errors:

(LET ((MEDIAN paste-the-above-lambda-expression-here))
  (LIST (MEDIAN '(2))
        (FUNCALL MEDIAN '(6 2 8 4))
        (FUNCALL 'MEDIAN '(2 4 6 8   1 3 5 7 9))
        (FUNCALL #'MEDIAN '(2 4 6 8   1 3 5 7 9   0))))
Filed under  //   control flow   evaluation  

Russian peasants

The Russian Peasant’s algorithm is a very simple way of multiplying 2 non-negative integers. The variant of the algorithm I am trying to implement is precisely described at the top of a Math Forum article.

In summary, repeatedly halve one of the factors (call it y), ignoring remainders, until it becomes zero; each time y is halved, double the other factor (x); the product is just the sum all x’s that occur when y is odd.

Here’s the offending function. It bombs out with a type error in all non-trivial cases:

(DEFUN PRODUCT (X Y)
  (DO ((X X (+ X X))
       (Y Y (FLOOR Y 2))
       (XY 0 (+ XY (IF (ODDP Y) X))))
      ((ZEROP Y) XY)))
Filed under  //   control flow   numbers  

Floating-point answer needed

This function is supposed to round a number to some given number of decimal places, returning a floating-point answer:

(DEFUN DECIMAL-PLACES (NUM PLACES)
  (LET ((SCALE (EXPT 10 PLACES)))
    (/ (ROUND (* NUM SCALE))
       SCALE)))

However, these results demonstrate that the present implementation isn’t returning floats:

(LIST (DECIMAL-PLACES 0.49 1)
      (DECIMAL-PLACES 1 2)
      (DECIMAL-PLACES 1/3 3))

=> (1/2 1 333/1000)
Filed under  //   numbers  

Inserting separators

A function is required to return a copy of a given list with separators added in between adjacent items, for example:

(SEPARATED-LIST '(1 -1 1 -1 1) 0)

=> (1 0 -1 0 1 0 -1 0 1)

This solution is incorrect due to a spurious separator at the end:

(DEFUN SEPARATED-LIST (ITEMS SEPARATOR)
  (LOOP FOR I IN ITEMS
        COLLECT I
        COLLECT SEPARATOR))
Filed under  //   iteration   sequences  

About

A growing compendium of erroneous Common Lisp code snippets by Ismail Ikram.

Lisp novices might try to correct these as a learning exercise. Need some help or just feel like nitpicking? Do post a comment and let me know.

Twitter