My def-server-struct Macro

Gene Michael Stover

created Thursday, 12 February 2004
updated Friday, 13 February 2004

Copyright © 2004 Gene Michael Stover. All rights reserved. Permission to copy, store, & view this document unmodified & in its entirety is granted.


Contents

1 Introduction

This is how I wrote my DEF-SERVER-STRUCT macro which was an important part of keeping a CGI/web project on schedule. Without it, I would have had to write much more code by hand, & the project would have required more time.

2 To Do

3 License

The source code in the file http://lisp-p.org/desest/def-server-struct.lisp & http://lisp-p.org/desest/test.lisp is released in accordance with the GNU Lesser General Public License. There is a copy of the license agreement at http://lisp-p.org/desest/COPYING.

This article is not covered by the Gnu Lesser General Public License. It is covered by its own copyright notice which is at the beginning of the article.

4 Obatining

The source code files are all at http://lisp-p.org/desest/. They are:


5 Motivation

I had to write a web application that had several data types in a data bank & allowed the CRUD operations on each of them. CRUD is an acronym for Create Read Update Delete, the operations commonly required on objects in a data bank.

Conceptually, it's a simple application, but if I had gone down the brute force implementation path, I would have needed to write a few CGI programs for each data type, each with one or more HTML templates, marshalling code, data-validation logic, & functions for the data bank. None of that code would have been difficult, but none of it would have been very interesting, either, & most of it would have been almost the same as the rest of it. So I thought up a way to write a simple Lisp program (``macro'' in Lisp terms) that would write all those functions for all those data types.


6 Using

fixme: Copied this section from ../jmt/. Modify it for the macro at hand.

This section is a brief tutorial. The full reference manual is in Section [*].

6.1 Load the Library

The first step to using this Mersenne Twister is to load it. You could load it into Lisp with a literal pathname, like this:

> (load "jmt.lisp") ; load from a literal pathname

or you could load from a logical pathname, like this:

;; Assuming cl-library already has some translations
;; defined for it.
> (push '("stover;jason;jmt.lisp" "jmt.lisp")
        (logical-pathname-translations "cl-library"))
> (load (translate-logical-pathname
          "CL-LIBRARY:STOVER;JASON;JMT.LISP"))
T

6.2 Generating Pseudorandom Numbers

The basic function for obtaining pseudoranom numbers from this Mersenne Twister is the MT-RANDOM function. It works like Common Lisp's RANDOM function.

With an integral argument $limit$, MT-RANDOM returns an pseudorandom integral number $r$ such that $0 <= r < limit$, like this:

> (loop for i from 1 to 5
        collect (mt-random 6))
(0 4 0 5 1)

What computer programmer hasn't played a roll-playing game?1Let's generate the six basic attributes for a character from an old edition of Dungeons & Dragons:

> (defun d6 () (1+ (mt-random 6)))
D6
> (defun roll-attr ()
    (+ (d6) (d6) (d6)))
ROLL-ATTR
> (loop for i from 1 to 6 collect (roll-attr))
(4 14 14 11 13 10)

With a floating point argument $limit$, MT-RANDOM returns a floating point pseudorandom number $0.0 <= r < limit$. Again, this is like the Common Lisp RANDOM function. Here is an example:

> (loop for i from 1 to 10
    collect (mt-random 1.0))
(0.03372876 0.2431892 0.99524146 0.0033221766
 0.6445225 0.6361625 0.89716256 0.35805753
 0.6595478 0.07814171)

6.3 Random States

Like the RANDOM function, MT-RANDOM allows an optional second argument. That second argument must be NIL or an instance of MT-RANDOM-STATE . If it is an MT-RANDOM-STATE , a copy of that state will be saved & used for future calls of MT-RANDOM unless you again use a state argument.

You can make a new MT-RANDOM-STATE with the MAKE-MT-RANDOM-STATE function. Let's make a pseudorandom random state now:

;; Use a PROGN so the random state isn't printed.
;; It's long & not pretty, I don't want to see it.
> (progn (setq rs (make-mt-random-state t)) nil)
NIL

Save a copy of the new random state so we can compare to it later:

> (progn (setq cs (make-mt-random-state rs)) nil)
NIL

Generate a few numbers with the new random state, RS:

> (mt-random 10 rs)
5
> (loop for i from 1 to 3 collect (mt-random 10))
(0 4 8)

By specifying RS again, we can repeat that same sequence of numbers & demonstrate that the MT-RANDOM-STATE found to RS was copied & not altered by MT-RANDOM :

> (mt-random 10 rs)
5
> (loop for i from 1 to 3 collect (mt-random 10))
(0 4 8)

6.4 Initialization

This Mersenne Twister stores its random state in the global variable *MT-RANDOM-STATE* much as the Common Lisp library stores its random state in *RANDOM-STATE* .

When you specify a non-NIL value as the second argument to MT-RANDOM-STATE , that value is bound to *MT-RANDOM-STATE* & used as the random state until you specify another value for it.

You may also use SETQ to bind an instance of MT-RANDOM-STATE to *MT-RANDOM-STATE* .

The *MT-RANDOM-STATE* global variable is specifically initiallized to a pseudorandom value when the library is loaded. Unless you need to recapture a sequence of random numbers or to continue a sequence from another process, it should not be necessary to initialize it specifically. I think this departs from Common Lisp's *RANDOM-STATE* global object, which is initialized to a constant value in many Lisp implementations.

A program might want to repeat a sequence of random numbers to repeat an output, possibly for legal reasons.

If many processes effectively share a random number generator, one process might want to load the generator's seed, use it for a while, & save it to a file before the process exited. That might be necessary for a web site implemented with CGI programs that needed to generate GUIDs.

A. Other File Formats

Bibliography

Fou
Free Software Foundation.
Lesser general public license.
world wide web.
http://www.gnu.org/licenses/licenses.html#LGPL.

Gene Michael Stover 2008-04-20