Someone (I've forgetten who, sorry) mentioned that Michael Stover had a new article up at lisp-p.org on parsing dates with Lisp, and when I went over to check it out I saw that Michael's been very busy; He's posted 22 new Lisp-related articles since the last time I checked, which was last June. Incredible.
Michael has also posted a brief article called ”What Happened to lisp-p.org?”, which while not exactly explaining the new lisp-p.org, does at least recognize that it is not now what it was initially aiming for (and states that it's going to stay the way it is).
Some of the articles are incomplete (or just short—the article on installing clisp ends when he is unable to install clisp on Red Hat Enterprise Workstation version 3, even with the help of the clisp maintainer), but here are a few that looked potentially interesting:
Speaking of slurping files, here's my version of a function to return the entire contents of a file as a string (for the record, as it were):
(defun contents-of-file (pathname) "Returns a string with the entire contents of the specified file." (with-output-to-string (contents) (with-open-file (in pathname :direction :input) (let* ((buffer-size 4096) (buffer (make-string buffer-size))) (labels ((read-chunks () (let ((size (read-sequence buffer in))) (if (< size buffer-size) (princ (subseq buffer 0 size) contents) (progn (princ buffer contents) (read-chunks)))))) (read-chunks))))))
Curiously, this turns out to be slightly slower in OpenMCL than Stover's version, which uses read-char and vector-push-extend. You'd think read-sequence and with-output-to-string would win, but apparently not.
Posted by jjwiseman at May 14, 2004 12:07 AMIf you're reading a disk file, you can allocate the whole buffer at once, skip all the copying, and give read-sequence the chance to slurp it in one swell foop. Using SBCL on Linux this version is almost 30x faster than yours. I'm pretty sure it's correct, but I haven't actually used it in anything yet.
(defun contents-of-file (pathname)
"Returns a string with the entire contents of the specified file."
(with-open-file (in pathname)
(let* ((bytes-to-read (file-length in))
(buffer (make-string bytes-to-read))
(bytes-read 0))
(loop until (= bytes-read bytes-to-read)
do (incf bytes-read
(read-sequence buffer in :start bytes-read)))
buffer)))
Yeah, it looks like OpenMCL is spending all its time writing to the string stream in my version. Making my buffer large enough to hold the entire file, it still takes as long as it did with a 4KB buffer.
Posted by: John Wiseman on May 14, 2004 09:28 AMI too had trouble believing your version would be slower (I am using it myself in some of my code). On LispWorks for Mac OS X, your code is easily 10 times faster than the 1 char at a time approach (and it conses 5 times less). OpenMCL is not always that efficient ;-)
Loading the whole file in 1 read solves the whole consing issue of course.
Posted by: Sven Van Caekenberghe on May 14, 2004 12:42 PMIt is true that if you're gonna read in the whole file eventually, you might as well make the buffer big enough to hold the whole thing right from the start.
...except that file-length doesn't necessarily tell you what you want to know in terms of bytes/characters.
So my current favorite is jsnell's version[1]:
(defun contents-of-file (pathname) "Returns a string with the entire contents of the specified file." (with-output-to-string (contents) (with-open-file (in pathname :direction :input) (let* ((buffer-size 4096) (buffer (make-string buffer-size))) (loop for size = (read-sequence buffer in) do (write-string buffer contents :start 0 :end size) while (= size buffer-size))))))
[1] http://paste.lisp.org/display/15131#1