I've been continuing learning/using Common Lisp. I'm actually getting to the point where I'm writing real code, and very much enjoying the language.
I can speak highly of Paul Graham's "ANSI Common Lisp" book. It's a good tutorial for someone familiar with programming concepts, but is also exhaustive (he does dismiss "loop"). Speaking of "loop", I've been using "iterate" <http://common-lisp.net/project/iterate/> instead. It gives most of the expressiveness of loop, but fits better into the syntax of lisp (which means that the editor indents it better). The nice thing is that it's just a normal lisp package, and works with whatever implementation I have. As a (somewhat perverse) example, I wrote this macro last night. (defmacro encode-packet ((sftp id) &body contents) (multiple-value-bind (length-constant lets length-terms) (iter (for (type form) :in contents) (let ((sym (gensym "FIELD"))) (collect `(,sym ,form) :into lets) (ecase type (byte (sum 1 :into length-constant)) (uint32 (sum 4 :into length-constant)) ((string byte-string) (sum 4 :into length-constant) (collect `(length ,sym) :into length-terms)) (packed-attributes (collect `(packed-attributes-length ,sym) :into length-terms)))) (finally (return (values length-constant lets length-terms)))) (let ((encoder (gensym "ENCODER")) (length (gensym "LENGTH"))) `(let* ((,id (next-packet-id)) ,@lets (,length (+ ,(+ 4 length-constant) ,@length-terms)) (,encoder (make-encoder ,length))) ,@(iter (for (type form) :in contents) (for (sym _) :in lets) (let* ((type-name (symbol-name type)) (encoder-name (concatenate 'string "ENCODE-" type-name))) (collect `(,(intern encoder-name) ,encoder ,sym)))) (send-packet ,sftp ,encoder) ,id)))) which takes an expression like: (encode-packet (sftp id) (byte +fxp-open+) (uint32 id) (string filename) (uint32 pflags) (packed-attributes (pack-attributes atts))) and turns it into: (LET* ((ID (NEXT-PACKET-ID)) (#:FIELD2107 +FXP-OPEN+) (#:FIELD2108 ID) (#:FIELD2109 FILENAME) (#:FIELD2110 PFLAGS) (#:FIELD2111 (PACK-ATTRIBUTES ATTS)) (#:LENGTH2113 (+ 17 (LENGTH #:FIELD2109) (PACKED-ATTRIBUTES-LENGTH #:FIELD2111))) (#:ENCODER2112 (MAKE-ENCODER #:LENGTH2113))) (ENCODE-BYTE #:ENCODER2112 #:FIELD2107) (ENCODE-UINT32 #:ENCODER2112 #:FIELD2108) (ENCODE-STRING #:ENCODER2112 #:FIELD2109) (ENCODE-UINT32 #:ENCODER2112 #:FIELD2110) (ENCODE-PACKED-ATTRIBUTES #:ENCODER2112 #:FIELD2111) (SEND-PACKET SFTP #:ENCODER2112) ID) It's complicated because the resulting code needs to pre-compute the length of the packet for the encoder, and then emit various pieces of code to encode the data in the packets. The SFTP packets contain variable length fields. I'm using this as part of a package I'm writing to talk to an SFTP server. David -- [email protected] http://www.kernel-panic.org/cgi-bin/mailman/listinfo/kplug-lpsg
