A Handful Of Useful Lisp Programming Tricks

Here are a few useful Lisp tricks, some are applicable to other languages.

Dynamic Variables

This is lisp 101, but if you have a parameter that many functions need and they access it at will and often, then it’s probably a good candidate for a dynamic variable.

A dynamic variable is like a global variable, but you can shadow its definition by using let:

(defvar *request*)

(defun serve (request) 
   (let ((*request* request))
      (declare (special *request*))
         ... ;; many operations work together handling requests, and they refer to the request often.
Fixed Point Math

Fixed point math is easy: you just imagine that some range of your integer is dedicated to holding values less than one unit. For example, you just decide that the value 1.0 (one unit) is the unsigned integer 10,000,000 thus any unsigned integer less than 10 million is less than one unit. This choice of unit gives about 7 decimals of accuracy but reduces the range of whole numbers to between 0 units and 429 units. You can perform calculations with scaled numbers, and print them using a scaling-aware print function.

(defun scaleup (n) (* 10000000 n))
(defun scaledown (n) (truncate n 10000000))
(defun scale-print (n)
  (multiple-value-bind (n r) (truncate n 10000000)
    (format t "~d.~7,'0d" n r)))

(scale-print (scaleup 1)) ==> 1.0000000

(defun *pi (n) (truncate (* n 355) 113))
(defun *e (n) (truncate (* n 2721) 1001))

(scale-print (*pi (scaleup 1))) ==> 3.1415929

You can use these just like regular numbers with one caveat: Multiplication and division need one scaled number and one unscaled number or you must downscale after multiplication and upscale after division. The order (downscale then multiply, or multiply then downscale) may affect the accuracy of the result.

Insurance against infinite loops

While developing, put this line into something you think will infinite-loop, this’ll stop it (at the cost of some false positives):

(and (zerop (random 1000)) (error "Infinite loop protect!"))
Normally distributed random integers

Sometimes you write tests that use random numbers, and sometimes the test is improved if those numbers tend to congest in an area. You can make a number generator that has a binomial pattern by adding two randoms togther. Don’t do (random 10) do (+ (random 5) (random 6)).

(defun bin-rand (n) (+ (random (ash (+ n 1) -1)) (random (ash (+ n 2) -1))))

;; Test It!
;; I got: #(354 676 967 1317 1686 1642 1357 1002 680 319)
(loop repeat 10000
       with vector = (make-array 10)
       for i = (bin-rand 10)
       do (incf (elt vector i))
       finally (return vector))
Compile Time Evaluation (compile-time-value)

Lisp has (load-time-value), which evaluates the form at load time, but it doesn’t have (compile-time-value) to do the same at compile time. That’s a shame because I wanted to load my CSS file and images into Lisp at compile time, so my saved image could serve requests for these frequently accessed files from memory without my having to put them on the server box.

Luckily, (compile-time-value) is very easy to write:

(defmacro compile-time-value (form) (eval form))

Using it, I used a slurp command I found on the internet, and was able to write my css handler.

(eval-when (:compile-toplevel :load-toplevel)
  (defun slurp (path)
    (with-open-file (stream (pathname path) :if-does-not-exist nil)
      (let ((seq (make-array (file-length stream) :element-type 'character :fill-pointer t)))
        (setf (fill-pointer seq) (read-sequence seq stream))

(defun handle-css (request) (http-send request (compile-time-value (slurp "mycss.css"))))
About these ads

2 Comments on “A Handful Of Useful Lisp Programming Tricks”

  1. (and (zerop (random 1000)) (error “Infinite loop protect!”))

    Haha, this is pretty awesome.

  2. formlis says:

    Glad you liked that one, in my opinion the best tip is compile-time-value… it’s so much easier than writing code to handle missing files.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Get every new post delivered to your Inbox.

Join 34 other followers