Just noticed an early version of arc has been released, certainly worth a look.
Archive for the ‘Lisp’ Category
Troels Henriksen rewrote the Climacs redisplay engine improving performance beyond compare. While there is alot of improvement still needed in terms of performance, features and polish, this change will make it viable for more people to use Climacs as a primary editor, so hopefully development will start to move faster.
If you haven’t tried Climacs or you were put off by its sluggish performance, now is a good time to try it out.
(defun human-sort (list &key (string-comparison #'string-lessp) (number-comparison #'<) (numbers-before-strings-p t)) (sort list (make-list-comp (make-alpha-num-comp string-comparison number-comparison numbers-before-strings-p)) :key #'split-alpha-num)) (defun make-list-comp (fun) (labels ((f (a b) (cond ((null b) nil) ((null a) t) ((funcall fun (first a) (first b)) t) ((funcall fun (first b) (first a)) nil) (t (f (rest a) (rest b)))))) #'f)) (defun make-alpha-num-comp (string-comp num-comp nums-before-strings-p) #'(lambda (a b) (cond ((and (stringp a) (stringp b)) (funcall string-comp a b)) ((and (numberp a) (stringp b)) nums-before-strings-p) ((and (stringp a) (numberp b)) (not nums-before-strings-p)) ((and (numberp a) (numberp b)) (funcall num-comp a b))))) (defun split-alpha-num (string) (pcond:pcond ((equal "" string) nil) ((:re "^(\\d+)(.*)" string ((#'parse-integer num) rest)) (cons num (split-alpha-num rest))) ((:re "^(\\D+)(.*)" string (alpha rest)) (cons alpha (split-alpha-num rest)))))
Unfortunately, the function SPLIT-ALPHA-NUM depends on PCOND which I’d rather not use. So I rewrote SPLIT-ALPHA-NUM using only standard Lisp:
(defun split-alpha-num (string) (mapcar #'parse-integer-if-integer (split-sequence-at-boundary #'digit-char-p string))) (defun parse-integer-if-integer (string) (or (parse-integer string :junk-allowed t) string)) (defun split-sequence-at-boundary (predicate sequence) (labels ((split1 (start predicate complement) (let ((end (position-if predicate sequence :start start))) (if end (cons (subseq sequence start end) (split1 end complement predicate)) (list (subseq sequence start)))))) (cond ((zerop (length sequence)) nil) ((funcall predicate (elt sequence 0)) (split1 0 (complement predicate) predicate)) (t (split1 0 predicate (complement predicate))))))
This version is longer, but it also produces SPLIT-SEQUENCE-AT-BOUNDARY which could potentially be reused in other contexts.
I recently reread the Tutorial on Good Lisp Programming Style by Peter Norvig and Kent Pitman. One thing that surprised me was the suggestion that it “may be appropriate sometimes” to use read macros to shorten lambda expressions:
(reduce #'+ numbers :key #L(if (oddp _) (* _ _) 0))
I’ve always avoided using that idiom because it’s non standard, but seeing it in such a highly regarded style guide is enough for me to add it to my bag of utilities. Here’s my definition:
#\# #\L #'(lambda (stream sub-character infix-parameter) (when infix-parameter (error "#~a does not take an integer infix parameter." sub-character)) `#'(lambda (,(intern "_"))
,(read stream t nil t))))
(I'd like to know how to prevent wordpress from mangling my code)
So I set up a blog and then promptly forgot about it, not a good start. I’ll endeavour to post once a month from now. Anyway, gigamonkey was asking for some link love for his book which was the real impetus behind this post.
According to Donald Knuth, Peter is now destined to write many more books, so I’ll take this opportunity to say ‘More Practical Common Lisp’ is a catchy title.
This blog will mostly be about Common Lisp.