Nov 18
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)
Oct 31
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))))
Oct 26
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)))
Oct 24
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)
Oct 23
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))