1
\$\begingroup\$

A fairly simple program that I tried to write in Common Lisp in order to practice/learn. I'm sure this can be done more elegantly but Lisp's string handling seems to be very werd.

(defun d20 () (+ 1 (random 19)))

(defun initlist (specs)
  (let* ((ilist (map 'list #'(lambda (n) `(,(first n) ,(+ (second n) (d20)))) specs))
         (sortedilist (sort ilist #'> :key #'second)))
    sortedilist))

(defun htmlinitlist (specs)
  (apply #'uiop:strcat `("<table><tr><td>&nbsp;</td><td>&nbsp;</td></tr>" 
   ,@(loop for (a b) in (initlist specs) collecting 
        (format nil "<tr><td>~A</td><td>~A</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td></tr>" 
                a b))
   "</table>")))

(defun htmlinitlists (specs count)
  (format nil "~{ ~A~}" (loop for i from 0 to count collecting (htmlinitlist specs))))

Sample usage from REPL:

(htmlinitlists '(("Elvish" 5) ("Wizgit" 2) ("Alaric" 8) ("Pounder" 6)) 17)
\$\endgroup\$
1
\$\begingroup\$

I wouldn't use strings at all. I would write to a stream.

If wished, I would convert the stream to a string.

(defun d20 () (+ 1 (random 19)))

initlist can be written more compact:

(defun initlist (specs)
  (sort (loop for (a b) in specs collect (list a (+ b (d20))))
        #'> :key #'second))

Now we pass a stream to htmlinitlist and write the contents to the stream:

(defun htmlinitlist (specs stream)
  (write-string "<table><tr><td>&nbsp;</td><td>&nbsp;</td></tr>" stream)
  (loop for (a b) in (initlist specs) do 
        (format stream
                "<tr><td>~A</td><td>~A</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td></tr>"
                a b))
  (write-string "</table>" stream))

If we want to get a string from a stream, we can use with-output-to-string. This binds a stream variable, which we can use and pass around...

(defun htmlinitlists (specs count)
  (with-output-to-string (stream)
    (write-char #\space stream)
    (loop repeat (1+ count) do (htmlinitlist specs stream))))

Alternate version of htmlinitlist using only one FORMAT call:

(defun htmlinitlist (specs stream)
  (format stream
          "<table><tr><td>&nbsp;</td><td>&nbsp;</td></tr>~
           ~{<tr><td>~A</td><td>~A</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td></tr>~}~
           </table>"
          (loop for (a b) in (initlist specs) collect a collect b)))

Benefit

All the various string operations (which are creating lots of intermediate strings which are immediately garbage) have been replaced with the usual output functions and a stream.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.