I’m learning Lisp and have written the following function to collect a list of results.
(defun collect (func args num)
(if (= 0 num)
()
(cons (apply func args)
(collect func args (- num 1)))))
It produced similar output to the built in loop function.
CL-USER> (collect #'random '(5) 10)
(4 0 3 0 1 4 2 1 0 0)
CL-USER> (loop repeat 10 collect (random 5))
(3 3 4 0 3 2 4 0 0 0)
However my collect function blows the stack when I try to generate a list 100,000 elements long
CL-USER> (length (collect #'random '(5) 100000))
Control stack guard page temporarily disabled: proceed with caution
Whereas the loop version doesn’t
CL-USER> (length (loop repeat 100000 collect (random 5)))
100000
How can I make my version more space efficient, are there alternatives to consing? I think it’s tail recursive. I’m using sbcl. Any help would be great.
Common Lisp implementations are not required by the ANSI standard to do tail call optimization; however, most that worth their salt (including SBCL) do optimize.
Your function, on the other hand, is not tail recursive. It can be turned into one by using the common trick of introducing an extra parameter for accumulating the intermediate result:
(The original parameters FUNC and ARGS are eliminated in the local function since they are constant with recpect to it).