Generate list of shape in Lisp I quickly created this function in Lisp that resembles 

numpy.random.randint(low, high=None, size=None, dtype='I')

The goal is simply to have a function that creates a list of random integers between low and high and that the list has a certain shape. I did not add the ability to choose the dtype as well, but this would be a possibility.

My function for doing this is the following:

(defun randint (&amp;key (start 0) end (shape '(1)))
  (if (&gt; (length shape) 3)
    (error "Shape can be maximally 3 long")
  (loop for i from 1 upto (first shape)
        if (not (null (rest shape)))
        collect (loop for j from 1 upto (first (rest shape))
                      if (not (null (rest (rest shape))))
                      collect (loop for k from 1 upto (first (rest (rest shape)))
                                    collect (+ start (random (+ 1 (- end start)))))
                      else
                      collect (+ start (random (+ 1 (- end start)))))
        else
        collect (+ start (random (+ 1 (- end start)))))))


Is there a more concise or more elegant way of writing this in Common Lisp?
Actually, I find the structure of the program quite complicated and difficult to read and understand. I think that the reason for this is that the program structure is patterned on the shape parameter, whose limitation to three elements is, in my opinion, rather arbitrary.

Why do not eliminate such limitation, and make the function more similar to the original numpy one, in which shape can be any list, even an empty list? 

The elimination of this restriction could seem to complicate the problem, but instead it simplifies the function if we use a recursive approach on the structure of shape:


if shape is empty, then generate a single random number
if shape is a list, get the first element, which is a number n, apply n times the function to the rest of the shape and collect the result in a list.


In this way the function is greatly simplified:

(defun randint (&amp;key (start 0) (end (1+ start)) (shape '()))
  (if (null shape)
      (+ start (random end))
      (loop as i below (car shape) collect (randint :start start :end end :shape (cdr shape)))))


Finally, I don't like the fact that a function has a key parameter which, if omitted, causes an error (end). So I would prefer to give it an optional value (for instance start + 1). Finally, to complete the similarity with the original function, I think we can default the shape parameter to the empty list, so that the call (randint :start n :end m) produce a single integer in the range specified.