<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://www.foldr.org/~michaelw/log/theme/style/rss.css" type="text/css"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xml:lang="en">

	<channel>
		<title>Random Bits and Pieces :: programming/lisp</title>
		<link>http://www.foldr.org/~michaelw/log</link>
		<description>Michael Weber</description>
		<language>en</language>
		<lastBuildDate>Sun, 27 Jan 2008 14:15:00 GMT</lastBuildDate>
		<generator>blosxom ver.2.0</generator>


		<item>
			<title>Munging Data with CLAWK</title>
			<link>http://www.foldr.org/~michaelw/log/programming/lisp/clawk</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/programming/lisp/clawk</guid>
			<category>http://www.foldr.org/~michaelw/log/programming/lisp/</category>
			<pubDate>Sun, 27 Jan 2008 14:15:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/programming/lisp/lisp.png" alt="Lisp Logo (by Conrad Barsky)" />

<p>Recently, I made good use
  of <a href="http://www.geocities.com/mparker762/">Michael
  Parker</a>'s <a
  href="http://www.geocities.com/mparker762/clawk">CLAWK</a>, a
  Lisp-embedded variant of <a
  href="http://en.wikipedia.org/wiki/AWK_(programming_language)">AWK</a>.
</p>

<p>So far, I had used the real AWK, along with perl and other parts of
  the Unix toolbox to analyze data from experiments, and munge it into
  HTML and LaTeX tables.  However, this time I expected the
  experiments to be carried out in
  a <q>run&ndash;tweak&ndash;rerun</q> fashion with several
  iterations, and I did not want to reparse several hundred megabytes
  each time, just for a change in table layout, or for adding another
  analysis.  (Also, I had not much time for lispy things recently, so
  this was a good way to sneak some Lisp back into my current C++
  hell...)
</p>

<p>
  Enter CLAWK.  The following function parses my benchmark data into
  Lisp objects:
</p>

<pre class="common-lisp"><code class="common-lisp"
><span class="paren">(</span><span class="keyword">defvar</span> <span class="variable-name">*foo-table*</span> <span class="paren">(</span>make-hash-table <span class="builtin">:test</span> 'equal<span class="paren">))</span>

<span class="paren">(</span>defawk parse-foo-benchmark <span class="paren">(</span><span class="type">&amp;aux</span> model<span class="paren">)</span>
  <span class="paren">(</span>#/^memtime/
   <span class="paren">(</span><span class="keyword">when</span> model
     <span class="paren">(</span>emit-model model *foo-table*<span class="paren">))</span>
   <span class="paren">(</span><span class="keyword">let</span> <span class="paren">((</span>path <span class="paren">(</span>parse-namestring $6<span class="paren">)))</span>
     <span class="paren">(</span>setf model <span class="paren">(</span>make-instance 'foo-model-record <span class="builtin">:filename</span> path<span class="paren">))))</span>
  <span class="paren">(</span>#/^Instantiator: Explored/
   <span class="paren">(</span>setf <span class="paren">(</span>get-states model<span class="paren">)</span> $#3
         <span class="paren">(</span>get-transitions model<span class="paren">)</span> $#6
         <span class="paren">(</span>get-bfs-levels model<span class="paren">)</span> $#9
         <span class="paren">(</span>completed? model<span class="paren">)</span> t<span class="paren">))</span>
  <span class="paren">((</span>string= $6 <span class="string">"elapsed"</span><span class="paren">)</span>
   <span class="paren">(</span>setf <span class="paren">(</span>get-generation-time model<span class="paren">)</span> $#5<span class="paren">))</span>
  <span class="paren">((</span>string= $13 <span class="string">"RSS"</span><span class="paren">)</span>
   <span class="paren">(</span>setf <span class="paren">(</span>get-generation-memory model<span class="paren">)</span> <span class="paren">(</span>parse-integer $15 <span class="builtin">:junk-allowed</span> t<span class="paren">)))</span>
  <span class="paren">(</span>END
   <span class="paren">(</span><span class="keyword">when</span> model
     <span class="paren">(</span>emit-model model *foo-table*<span class="paren">))</span>
   *foo-table*<span class="paren">))</span>
</code></pre>

<p>Parsing the bulk of my data with the above function takes about
  80&nbsp;seconds, probably slower than it would be with AWK.
  However, once parsed I have all the data available at my fingertips
  inside the Lisp image.  I can prod it with
  the <a href="http://common-lisp.net/project/slime/">SLIME</a>
  inspector, identify outliers, and play around with it in the REPL
  until I am satisfied.  In addition, I can selectively rerun parts of
  the experiments, and parse just the newly produced output to update
  the in-memory representation, again in no time flat.  Beats the Unix
  <q>everything is a byte stream</q> way every day of the week.  
</p>
<p>Rendering the results as HTML is a breeze
  with <a href="http://weitz.de/cl-who/">CL-WHO</a>.  The same holds
  for reordering columns, marking interesting entries
  programmatically, cross-referencing with other entries (or earlier
  versions of the data) and refining the analyses as much as I wish,
  with instant feedback.
</p>

<p style="margin-top:4ex;">
  Unfortunately, CLAWK has acquired some bitrot since its release in
  2002&nbsp;(?).  I needed to tweak it slightly to make it compile
  (only tested with <a href="http://www.sbcl.org/">SBCL</a>).  When I
  tried to contact Michael Parker, his email bounced, so I decided to
  put up a patched version locally until the changes are folded back
  into his distribution.  In
  addition, <a href="http://www.foldr.org/~michaelw/lisp/clawk/#clawk">CLAWK is now
  ASDF-installable</a> (along with its
  dependency, <a href="http://www.foldr.org/~michaelw/lisp/clawk/#regex">REGEX</a>),
  courtesy of
  <a href="http://www.foldr.org/~michaelw/lisp/redshank/">Redshank</a>'s ASDF Defsystem
  skeleton.
</p>

<p>If time permits, I will fix up the code some more to get rid of the
  warnings, and perhaps
  allow <a href="http://weitz.de/cl-ppcre/">CL-PPCRE</a> as
  alternative regular expression engine.  However, patches from the
  open-source fairies are very welcome, too.
</p>
]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/programming/lisp/clawk#writeback</comments>
		</item>

		<item>
			<title>Common Lisp Editing Extensions?  I'll Show You the Bird...</title>
			<link>http://www.foldr.org/~michaelw/log/programming/lisp/redshank</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/programming/lisp/redshank</guid>
			<category>http://www.foldr.org/~michaelw/log/programming/lisp/</category>
			<pubDate>Tue, 25 Sep 2007 07:09:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/programming/lisp/lisp.png" alt="Lisp Logo (by Conrad Barsky)" />

<p>
  In best <a href="http://bc.tech.coop/blog/">billc</a> style... ;^)<br /> I
  have mentioned some of my <a href="http://www.foldr.org/~michaelw/emacs/">Emacs
  hacks</a> for editing Common Lisp code
<a href="http://www.foldr.org/~michaelw/log/programming/lisp/defpackage-skeleton">here</a>,
<a href="http://www.foldr.org/~michaelw/log/programming/lisp/defclass-skeleton">here</a>,
and <a href="http://www.foldr.org/~michaelw/log/programming/lisp/defclass-formatter">here</a> (the
latter of which <a href="http://sigkill.dk/">Troels
Henriksen</a> <a
href="http://sigkill.dk/code/climacs-defclass-prettifier.lisp">ported
to</a>
<a href="http://common-lisp.net/project/climacs/">Climacs</a>).
So, I finally dusted off some more code-wrangling Emacs macros and
bundled them up in
the <a href="http://www.foldr.org/~michaelw/lisp/redshank/">Redshank
minor mode</a>.  Obligatory screencast:</p>

<a href="http://www.foldr.org/~michaelw/lisp/redshank/"
><img class="center"
      src="http://www.foldr.org/~michaelw/log/static/programming/lisp/redshank.png"
      alt="Still of Redshank Screencast" /></a>

<p>
  The provided functionality is quite embryonic still, but I expect it
  to continue to grow.
</p>

<p>
  For actual code motion and manipulation of Lisp code, I heavily rely
  on the
  excellent <a
  href="http://www.emacswiki.org/cgi-bin/wiki/ParEdit">Paredit</a>
  mode, with a minimal dependency
  on <a href="http://common-lisp.net/project/slime/">SLIME</a> (the
  dependency might grow in the future, as more sophisticated
  refactoring likely requires cooperation from a running Lisp.)
</p>

<p>
  For <strike>laughs</strike> comparison, I'd like to see the same
  done for
  <a href="http://www.foldr.org/~michaelw/log/programming/lisp/lispin">unparenthesized code</a>...<br />
  Okay, <a href="http://c2.com/cgi/wiki?SmugLispWeenie">enough smugness</a>
  for today.  Now read the
  best <a href="http://gigamonkeys.com/book/">Common Lisp
  Tutorial</a>, and start hacking away!
</p>

<h3>First Reactions after Prerelease to <strike>the Raving
Masses</strike> a Priviledged Audience</h3>

<pre>
antifuchs | michaelw: o_O this is awesome

     jmbr | michaelw: I've just downloaded redshank. It's quite cool!

 michaelw | pkhuong: eh, okay ECONTEXT :) defclass-skeleton now
            inserts parenthesis balanced
  pkhuong | michaelw: ah good, good! I might have to try it out then
 michaelw | (bonus: customizable accessor style)
  pkhuong | so I can have foo-of instead of get-foo too? That
          | was my other objection (:

     Xach | I am eagerly awaiting the Planet Lisp link!
</pre>

<p>
  p.s.: In the right window of the screencast, key strokes were
  recorded with <a
  href="http://www.foldr.org/~michaelw/log/programming/lisp/mwe-log-commands">mwe-log-commands</a>.
</p>
<p>
  p.p.s: The screencasting itself was a major pain.  In this case, I am
  willing to put part of the blame on my inexperience, for the rest I
  blame the tools I used.  A somewhat more detailed account of this
  may appear under the <a href="http://www.foldr.org/~michaelw/log/rants/">Rants</a> section.
</p>
]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/programming/lisp/redshank#writeback</comments>
		</item>

		<item>
			<title>MORE SKELETONS</title>
			<link>http://www.foldr.org/~michaelw/log/programming/lisp/defclass-skeleton</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/programming/lisp/defclass-skeleton</guid>
			<category>http://www.foldr.org/~michaelw/log/programming/lisp/</category>
			<pubDate>Mon, 13 Aug 2007 12:16:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/programming/lisp/lisp.png" alt="Lisp Logo (by Conrad Barsky)" style="max-width: 9em; float: right; clear: right;" />

<p>
  Somebody in <a href="asked on comp.lang.lisp about a
http://groups.google.com/group/comp.lang.lisp/msg/31fdd6399377f7d5">comp.lang.lisp asked about a
  <code class="common-lisp">DEFCLASS</code> skeleton</a>, after I showed
  a <a
  href="http://www.foldr.org/~michaelw/log/programming/lisp/defpackage-skeleton"><code
  class="common-lisp">DEFPACKAGE</code> skeleton</a> earlier.
  So, here it is:
</p>

<pre class="common-lisp"><code class="common-lisp">
<span class="paren">(</span><span class="keyword">define-skeleton</span> <span class="function-name">mwe:cl-defclass-skeleton</span>
  <span class="doc">"Inserts a Common Lisp DEFCLASS skeleton."</span>
  <span class="string">"Class: "</span>
  <span class="string">"(defclass "</span> str <span class="string">" ("</span> <span class="paren">((</span>skeleton-read <span class="string">"Superclass: "</span><span class="paren">)</span> str <span class="string">" "</span><span class="paren">)</span> &amp; -1 <span class="string">")"</span>
  \n <span class="string">"("</span> <span class="paren">((</span>skeleton-read <span class="string">"Slot: "</span><span class="paren">)</span>
          <span class="string">"("</span> str <span class="string">" :accessor get-"</span> str <span class="string">" :initarg :"</span> str <span class="string">")"</span> \n<span class="paren">)</span> &amp; '<span class="paren">(</span>join-line<span class="paren">)</span>
  <span class="string">")"</span>
  <span class="comment-delimiter">;; </span><span class="comment">\n "(:default-initargs " - ")" ;; add to your liking...
</span>  <span class="string">")\n"</span> \n
  _<span class="paren">)</span>

<span class="paren">(</span><span class="keyword">define-skeleton</span> <span class="function-name">mwe:cl-defclass-slot-skeleton</span>
  <span class="doc">"Inserts a Common Lisp DEFCLASS slot skeleton."</span>
  <span class="string">"Slot: "</span>
  <span class="paren">((</span>skeleton-read <span class="string">"Slot: "</span><span class="paren">)</span>
   <span class="string">"("</span> str <span class="string">" :accessor get-"</span> str <span class="string">" :initarg :"</span> str <span class="string">")"</span> \n<span class="paren">)</span> &amp; '<span class="paren">(</span>join-line<span class="paren">)</span>
  _<span class="paren">)</span>
</code></pre>

<p>I have not felt a need for it so far, mostly because it turns out
  that my <code class='common-lisp'>DEFCLASS</code> forms rarely are
  that regular, and tend to grow iteratively, so I have to go back and
  change them anyway.  Using skeletons then feels to me like
  interrupting the <q>flow</q>, for lack of a better explanation...
</p>

<p>
  Also, I would rather have somebody step forward and publish
  their <a
  href="http://www.bloomington.in.us/~brutt/msf-abbrev.html">msf-abbrev</a>
  abbreviations for Common Lisp.  Thanks.
</p>
<h3><a id="defclass-skeleton-1" class="updatetitle">UPDATE 2008-01-08: Old News...
</a><br /></h3>
<div><p>
The above skeleton is part
of <a
href="http://www.foldr.org/~michaelw/log/programming/lisp/redshank">Redshank</a>
mode now.
</p>
</div>

]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/programming/lisp/defclass-skeleton#writeback</comments>
		</item>

		<item>
			<title>Skeletons in the CLoset...</title>
			<link>http://www.foldr.org/~michaelw/log/programming/lisp/defpackage-skeleton</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/programming/lisp/defpackage-skeleton</guid>
			<category>http://www.foldr.org/~michaelw/log/programming/lisp/</category>
			<pubDate>Fri, 10 Aug 2007 22:17:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/programming/lisp/lisp.png" alt="Lisp Logo (by Conrad Barsky)" style="max-width: 9em; float: right; clear: right;" />

<p>Some time ago, <a href="http://xach.livejournal.com/">Xach</a>
mentioned his
<a href="http://www.gnu.org/software/emacs/manual/elisp.html">Elisp</a> snippet
which <a
href="http://xach.livejournal.com/130040.html">inserts <code
class="common-lisp">DEFPACKAGE</code> forms into the current buffer</a>.
</p>

<p>I finally beefed up my version a little, so that it uses Emacs'
  buffer filename as default package name.  For quick dabbling,
  visiting a new file and typing <kbd>RET RET RET</kbd> is enough.
  Otherwise, packages to be <code class='common-lisp'>USE</code>d can be autocompleted
  from the lists of loaded packages, thanks
  to <a href="http://common-lisp.net/project/slime/">SLIME</a>.
</p>

<p>Here goes:</p>

<pre class="common-lisp"><code class="common-lisp">
<span class="paren">(</span><span class="keyword">define-skeleton</span> <span class="function-name">mwe:cl-defpackage-skeleton</span>
  <span class="doc">"Inserts a Common Lisp DEFPACKAGE skeleton."</span>
  <span class="paren">(</span>skeleton-read <span class="string">"Package: "</span> <span class="paren">(</span><span class="keyword">if</span> v1
                                 <span class="paren">(</span>file-name-sans-extension
                                  <span class="paren">(</span>file-name-nondirectory
                                   <span class="paren">(</span>buffer-file-name<span class="paren">)))))</span>
  <span class="paren">(</span><span class="keyword">if</span> <span class="paren">(</span>setq v1 <span class="paren">(</span>bobp<span class="paren">))</span> <span class="string">";;; -*- Mode:Lisp; Syntax:ANSI-Common-Lisp;"</span><span class="paren">)</span>
  &amp; <span class="paren">(</span><span class="keyword">if</span> buffer-file-coding-system
        <span class="paren">(</span>concat <span class="string">" Coding:"</span>
                <span class="paren">(</span>symbol-name 
                 <span class="paren">(</span>coding-system-get buffer-file-coding-system 
                                    'mime-charset<span class="paren">))))</span>
  &amp; <span class="string">" -*-"</span>
  &amp; \n
  &amp; \n <span class="string">"(defpackage #:"</span> str
  \n <span class="string">"(:nicknames"</span> <span class="paren">(</span><span class="string">"Nickname: "</span> <span class="string">" #:"</span> str<span class="paren">)</span> &amp; <span class="string">")"</span> | '<span class="paren">(</span>kill-whole-line -1<span class="paren">)</span>
  \n <span class="string">"(:use #:CL"</span> <span class="paren">((</span>slime-read-package-name <span class="string">"USEd package: "</span><span class="paren">)</span> <span class="string">" #:"</span> str<span class="paren">)</span> <span class="string">")"</span>
  <span class="string">")"</span> \n
  \n
  <span class="paren">(</span><span class="keyword">if</span> v1 <span class="string">"(in-package #:"</span><span class="paren">)</span> &amp; str &amp; <span class="string">")"</span> &amp; \n &amp;
  \n
  _<span class="paren">)</span>
</code></pre>

<p>Works
  with <a
  href="http://www.emacswiki.org/cgi-bin/wiki/SkeletonMode">skeleton
  mode</a>
  from <a href="http://www.gnu.org/software/emacs/">GNU Emacs</a>
  (version 22.0.92).  First-time users of <code>autoinsert</code>
  might want to use the following additional setup:
</p>

<pre><code>
(eval-after-load 'autoinsert
  '(progn
     (push '(lisp-mode . mwe:cl-defpackage-skeleton) auto-insert-alist)
     (auto-insert-mode +1)))

(require 'autoinsert)
</code></pre>

<p>It is also possible to just <kbd>M-x
    mwe:cl-defpackage-skeleton</kbd>.  If done somewhere else than at the
    beginning of a buffer, the comment
    and <code class='common-lisp'>IN-PACKAGE</code> form is not
    generated (useful for a <tt>packages.lisp</tt> file containing
    multiple package forms.)
</p>
<h3><a id="defpackage-skeleton-1" class="updatetitle">UPDATE 2008-01-08: Old News...
</a><br /></h3>
<div><p>
The above skeleton is part
of <a href="http://www.foldr.org/~michaelw/log/programming/lisp/redshank">Redshank</a>
mode now.
</p>
</div>

]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/programming/lisp/defpackage-skeleton#writeback</comments>
		</item>

		<item>
			<title>Knuth-Morris-Pratt Search</title>
			<link>http://www.foldr.org/~michaelw/log/programming/lisp/kmp-search</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/programming/lisp/kmp-search</guid>
			<category>http://www.foldr.org/~michaelw/log/programming/lisp/</category>
			<pubDate>Sat, 17 Mar 2007 17:16:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/programming/lisp/lisp.png" alt="Lisp Logo (by Conrad Barsky)" />

<p>
  <a href="http://boinkor.net/">Andreas Fuchs</a> wrote a 
  <a
  href="http://boinkor.net/archives/2007/03/simple_visualization_tool_for.html">visualization
  tool for string search</a>.  I could not resist to add
  the <a
  href="http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm">Knuth-Morris-Pratt</a>
  algorithm, given that it was just a handful code for the algorithm
  itself,
  the <a
  href="http://www.foldr.org/~michaelw/lisp/antifuchs-clim-search-visualizer.png">visualization</a> <a
  href="http://boinkor.net/lisp/porn/barabas-KMP.png">then</a> <a
  href="http://boinkor.net/lisp/porn/barabas-BM.png">comes</a> <a
  href="http://boinkor.net/lisp/porn/it-looks-like-this.png">for
  free</a>, thanks to Andreas' preparatory work.
</p>

<p>
  That reminded me, however, that I have
  a <a href="http://www.foldr.org/~michaelw/lisp/kmp-search.lisp">KMP
  implementation</a> lying around.  The KMP algorithm is easy to
  implement, and works well with streams:
</p>

<pre class='common-lisp'><code class='common-lisp'>
KMP> <span class="paren">(</span><span class="keyword">with-input-from-string</span> <span class="paren">(</span>s <span class="string">"12345AaAaB67890"</span><span class="paren">)</span>
       <span class="paren">(</span><span class="keyword">let</span> <span class="paren">((</span>ts <span class="paren">(</span>make-array 10 <span class="builtin">:element-type</span> 'character
                             <span class="builtin">:adjustable</span> t <span class="builtin">:fill-pointer</span> 0<span class="paren">)))</span>
         <span class="paren">(</span>do-delimited-stream
             <span class="paren">((</span>token expected <span class="paren">(</span>read-char s<span class="paren">)</span>
                     <span class="paren">(</span>multiple-value-call #'values ts <span class="paren">(</span>read-line s nil<span class="paren">)))</span>
              <span class="string">"AAB"</span>           <span class="comment-delimiter">; </span><span class="comment">restart-vector generated automatically
</span>              <span class="builtin">:predicate</span> #'char-equal<span class="paren">)</span>
           <span class="paren">(</span>vector-push-extend token ts<span class="paren">)</span>
           <span class="paren">(</span>format *trace-output* <span class="string">"~&amp;Expected ~A, got ~A"</span> expected token<span class="paren">))))</span>
Expected A, got 1
Expected A, got 2
Expected A, got 3
Expected A, got 4
Expected A, got 5
Expected A, got A
Expected A, got a
Expected B, got A
Expected B, got a
Expected B, got B
"12345AaAaB"
"67890"
T
KMP> 
</code></pre>

<p>
  KMP works in a way that it does not have to backtrack on the stream
  after a partial match, unlike a na&iuml;ve algorithm.  Neither does it
  store parts of the stream.
</p>
<p>
  I used it to read from a stream until the given delimiter is
  reached, and save everything upto and including the delimiter for
  further processing.  Since it does not seize control of the stream
  I can, for example, process escape sequences or skip parts of the
  stream, before I hand stream elements
  to <code class='common-lisp'>DO-DELIMITED-STREAM</code>.
</p>
]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/programming/lisp/kmp-search#writeback</comments>
		</item>

	</channel>
</rss>
