<?xml version="1.0" encoding="utf-8"?> 
<feed xmlns="http://www.w3.org/2005/Atom"> 
 <title>unbalanced-parentheses</title> 
 <id>http://unbalanced-parentheses.nfshost.com/</id> 
 <subtitle> fun with newLISP! </subtitle> 
 <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/" />  
 <link rel="self" type="application/atom+xml" href="http://unbalanced-parentheses.nfshost.com/atom.cgi" /> 
 <updated>2008-08-20T16:44:22Z</updated> 
 <author> 
   <name>newlisp</name>  
 <uri>http://unbalanced-parentheses.nfshost.com/</uri> 
 </author>
 
<entry>
   <title>Reasons to learn newLISP</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/reasonstolearnnewlisp" /> 
   <id>http://unbalanced-parentheses.nfshost.com/reasonstolearnnewlisp</id> 
   <published>2008-08-20T16:44:22Z</published>
   <updated>2008-08-20T16:44:22Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>It's that time of the year when many people face new academic challenges, so now's a great time to learn newLISP! Here are some - frankly quite biased - suggestions as to why newLISP is a good choice for a first - or second or third - programming language. By the way, most of these suggestions are true of most programming languages. </p>

<h2>1 It's easy</h2>

<p>newLISP is easy to download, install, and use. For most operating systems you'll find an installer and/or prebuilt versions. You won't have to build, compile, or make the software, and running it is as easy as typing its name.</p>

<p>It's easy to program in, too. The carefully-designed syntax aims for readability and write-ability, without introducing too many special forms and conventions. Obscure function names have been replaced by more English-like ones, and the temptation to make use of every punctuation mark known to humankind has been resisted, for the most part. Although sadly I don't think we'll ever be able to say goodbye regular expressions. And there are some great introductory tutorials too. (I wrote one of them, so I'm biased!)</p>

<p>'easy' isn't always the main reason for doing anything. Sometimes we do things not because they're easy, but because they are hard. Sometimes we have to use things that aren't easy to use to solve hard problems. But easy can be good when you're learning something new. You probably didn't learn to drive a car in a Ferrari...</p>

<h2>2 It's small</h2>

<p>It would be hard to find a memory card on sale today with a capacity too small to hold newLISP - if you can find a 512KB memory card you'll have plenty of room to spare. </p>

<p>More seriously: it's a compact language that tries to provide everything you need and dispenses with much that you don't. With about 350 functions, it's a reasonably complete basic programmer's toolkit without the complexity and advanced features of the larger languages. You can worry about making it bigger - or moving to a bigger language - later, when (or if) you outgrow it.</p>

<p>Yes, it hasn't got sub-atomic reference de-clustering, quasi-optimal cyclical redundancy, or meta-stable bytecode traversal, to name just a few of the language's most obvious omissions, but there's plenty of useful tools to get you started. (I made those up, by the way, but that doesn't mean that they don't actually exist...)</p>

<h2>3 It's fast</h2>

<p>newLISP is quick enough for most purposes, so you shouldn't have too many problems with speed. For extra performance you can learn how to link to compiled C libraries, or write assembly code (two things which I've managed to avoid so far). The 50,000 word introduction I mentioned above is translated in about 0.4 seconds, which is too quick for me - better to take 10 seconds so that I can drink some coffee...</p>

<h2>4 It's versatile</h2>

<p>Use newLISP to explore programming concepts, crunch numbers, write internet applications, analyze text documents, post rubbish to blogs, or compose music. You can learn many different styles of programming in newLISP: casual scripting (my favourite!), imperative programming, functional programming, object-oriented programming, and even a form of macro programming - you'll be working with newLISP for a long time before you've exhausted newLISP's potential and are ready to move on to bigger and more complex languages (if you want to). Instead of just following what other people tell you is the 'right' way, why not try the different styles and make your own mind up?</p>

<p>You don't have to be a computer scientist to use newLISP: musician, writer, artist, sysadmin, architect, web developer, surveyor, mathematician, tinker, tailor, soldier, sailor - if your work involves the computer, it could benefit if that computer works harder for you.</p>

<p>This is the sort of newLISP I use all the time:</p>

<pre><code>(set 'dir (real-path))
(dolist (i (directory dir {^[^.]}))
 (set 'item (string dir "/" i))
 (set 'mod-date (date (file-info item 6) 0 "%Y%m%d-%H%M%S"))
 (rename-file item (string dir "/" mod-date i)))
</code></pre>

<p>which simply renames files based on their modification dates. But others are into newLISP like this:</p>

<pre><code> (let ((g (lambda (h) 
          (expand (lambda (n) 
            (let ((f (lambda (f n) 
                    (if (&lt; n 2) 1 (* n (f (- n 1))))))) 
            (f (h h) n))) 'h))))
       ((g g) 10)) 
</code></pre>

<p>which is something to do with the <a href="http://www.newlisp.org/index.cgi?Y_Function">Y function</a>.</p>

<h2>5 It's different</h2>

<p>newLISP is certainly not your Dad's Lisp, and there's plenty of tutting in some of the online communities who get easily worked up by the different. But perhaps you're ready to find out for yourself what you think is good or bad, and perhaps you like to avoid doing the obvious and predictable. Or at least prove to your own satisfaction that your Dad was right all along.</p>

<h2>6 It's friendly</h2>

<p>On the newLISP forum, genuine questions usually receive genuine answers. You probably won't encounter the uncompromising attitudes that newcomers to other languages <a href="http://social-problems-of-lisp.blogspot.com/">occasionally encounter</a>. You might even get help from Lutz, the language's author.</p>

<h2>7 It's not finished</h2>

<p>newLISP is still developing. There's room for contributions from you: plenty of investigations and discoveries still to be made, plenty of code and applications still to be written, and many subjects for writing and blogging about. If you want to take an active part in its development, there are plenty of oportunities waiting for you. You might even get your own function included in the next release (but it will have to be a <em>really</em> good idea!). It won't be named after you, though.</p>

<h2>8 It's fun</h2>

<p>Is programming fun? It's not always fun; sometimes the code doesn't do what you thought you told it to do. But newLISP has got to be fun, because the slogan says it is!</p>

<h2>9 It's free</h2>

<p>Of course, sometimes the best things in life are free!</p>
        
]]></content>
  </entry>


<entry>
   <title>Two (or more) challenges for the weekend</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/twoormorechallengesfortheweekend" /> 
   <id>http://unbalanced-parentheses.nfshost.com/twoormorechallengesfortheweekend</id> 
   <published>2008-08-02T09:07:41Z</published>
   <updated>2008-08-02T09:07:41Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>What's the point of the following line at the start of this newLISP blog script?</p>

<pre><code>(if (unless nil nil true) (exit))
</code></pre>

<p>See if you can get your comment through the impassable barrier that is the newLISP Bayesian Comment Spam Killer below! (No, it won't kill Bayesian comemnts - although it might - but it tries to kill spam comments using Bayesian analysis.)</p>
        
]]></content>
  </entry>


<entry>
   <title>Comment on twoormorechallengesfortheweekend from Alessandro</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/twoormorechallengesfortheweekend" /> 
   <id>http://unbalanced-parentheses.nfshost.com/twoormorechallengesfortheweekend2008-08-15T21:21:21Z</id>
   <author>
     <name>Alessandro</name>
     <uri>http://newlisp.wordpress.com</uri>
   </author>
   <published>2008-08-15T21:21:21Z</published>
   <updated>2008-08-15T21:21:21Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>This comment are is really interesting!
And I'm happy now I can submit comments to your great articles!
Thank you for this snippet! :-)</p>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>Comment on twoormorechallengesfortheweekend from tom</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/twoormorechallengesfortheweekend" /> 
   <id>http://unbalanced-parentheses.nfshost.com/twoormorechallengesfortheweekend2008-08-20T03:50:58Z</id>
   <author>
     <name>tom</name>
     <uri>around somewhere.</uri>
   </author>
   <published>2008-08-20T03:50:58Z</published>
   <updated>2008-08-20T03:50:58Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>I haven't stopped by to look lately; love what you've done with the place.</p>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>Looking for things</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/lookingforthings" /> 
   <id>http://unbalanced-parentheses.nfshost.com/lookingforthings</id> 
   <published>2008-07-31T18:42:14Z</published>
   <updated>2008-07-31T18:42:14Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>When writing newLISP, it's often useful to find any existing code that uses a particular function or symbol name. I'm a fan of both the Unix <em>find</em> command and the Mac's built-in search tool, Spotlight. The former is all-powerful, but it can be a little tricky to remember all those options. The latter is particularly good for finding text in documents - not just text files - since many developers provide a Spotlight system plug-in for searching their own document types. </p>

<p>Naturally, though, I also use a small newLISP utility alongside these two: its purpose is to look only in places where there are newLISP-related files. I reworked this recently based on some suggestions in the newLISP forum. Here's the code:</p>

<pre><code>#!/usr/bin/env newlisp
(context 'Look4)

(constant 'extensions '("lsp" "txt" "html")) 

(set 'places 
  (list (string (env "HOME") "/projects/lisp")
        (string (env "HOME") "/projects/webapps")
        (string (env "HOME") "/projects/guiapps")
        (string (env "HOME") "/projects/tech-writing")
        "/usr/share/newlisp"))

(define (string-ends-with L str) 
  (exists (fn (x) (ends-with str x)) L))

(define (look-in-file pn)
 (let (contents "" res '())
  (when (string-ends-with extensions pn)
     (set 'file (open pn "r"))
     (while (search file (string "(.*?" Term ".{10,20})") true 1)
        (push $1 res -1))
     (close file)
     (if res (list pn res)))))

(define (Look4:Look4 dir)
   (dolist (nde (directory dir "^[A-z]"))
     (set 'item (append dir "/" nde))
     (if (directory? item)
       (Look4 item)
       (when (set 'r (look-in-file item Term)) (inc 'counter) (push r results)))))

(when (&gt;= (length (main-args)) 2) 
  (set 'Term (main-args 2) 'counter 0)
  (map Look4 places)
  (when results
    (sort results)
    (dolist (r results)
        (println "\n" (r 0) "\n\t\t\t")
        (dolist (e (r 1)) (println "\t" e)))
        (println "Found " counter " occurrences of \"" Term "\"")))

(exit)
</code></pre>

<p>You can see that I've hardwired the names of the directories to search in. That's not very flexible, but it may suit your working style.</p>

<p>On the command line, you run the script and supply a string:</p>

<pre><code>$ look4 unless
</code></pre>

<p>and you'll see the results in a couple of seconds:</p>

<pre><code>...
/Users/me/projects/lisp/tokenizer.lsp

    (unless txt (exit))

/usr/share/newlisp/guiserver.lsp

;; a Piano instrument unless the function 'gs:mi

/usr/share/newlisp/modules/smtp.lsp

      (unless (and (empty?  user-

/usr/share/newlisp/util/nanorc

color blue "([[:space:]()]|^)(trim|true|true\?|unicode|unify|unique|unless|unpack|until|upper-
...

Found 201 occurrences of "unless"
$ 
</code></pre>

<p>Since the search is a regular expression one, it <em>might</em> be possible to supply a regex-friendly string, if you escape all the regex characters, but I find that I rarely use regular expressions in this type of search. I'm more likely to be asking "Didn't I once write a <em>binary</em> function?".</p>
        
]]></content>
  </entry>


<entry>
   <title>Character reference</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/characterreference" /> 
   <id>http://unbalanced-parentheses.nfshost.com/characterreference</id> 
   <published>2008-07-25T21:46:33Z</published>
   <updated>2008-07-25T21:46:33Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>I was looking through an old (1990!) book on Unicode the other day. I've always been intrigued by the amazing diversity of letter forms that we've created over the last few thousand years. Here are just some of the many wonderful and peculiar characters you'll find tucked away in the Unicode glyph banks:</p>

<ul>
<li>۞</li>
<li>ⱁ</li>
<li>ᚅ</li>
<li>Ꮈ</li>
<li>Ϣ</li>
<li>܍</li>
</ul>

<p>You'll also find the I Ching, Braille, alchemy, an alphabet funded by George Bernard Shaw, neo-pagan tree language, astrology, dentists, talking leaves, and much more besides.</p>

<p>Most of the technical aspects of Unicode escape me (supplementary planes, normalization, high surrogates, collation?) but it's useful to know the basics of using Unicode in newLISP, particularly now that it's <a href="http://googleblog.blogspot.com/2008/05/moving-to-unicode-51.html">the most popular encoding used on the internet</a>.</p>

<p>newLISP is UTF-8 friendly by default on MacOS X, and UTF-8 versions are available for other platforms too (although I'm not sure whether the default versions are UTF-8). UTF-8 is a variable-length character encoding, which allows characters to use 1, 2, 3 or 4 bytes depending on their Unicode value.</p>

<p>One essential newLISP function for exploring the Unicode character set is <em>char</em>. This takes either a number or a character, and returns the matching character or number:</p>

<pre><code>(char 63498)
""

(char "")
63498
</code></pre>

<p>Unicode characters are usually described using hexadecimal, so it's useful to know how to translate between hex and decimal. To convert a decimal integer to a hex string, use <em>format</em>:</p>

<pre><code>(format "%llx" 63498)
"f80a"
</code></pre>

<p>To convert a hex string to a decimal integer, pass a hexadecimal string starting with "0x" to <em>int</em> :</p>

<pre><code>(int (string "0x" "f80a"))
63498
</code></pre>

<p>When you're writing text, it would be good if you could easily insert these characters as you type. There are useful system tools for doing this (on MacOS X, there's the Character Palette), but for fun I've added the following two functions to the Markdown converter that I use to process my writing:</p>

<pre><code>(define (hex-str-to-unicode-char strng)
   (char (int (string "0x" (1 strng)) 0 16)))

(define (ustring s)
  (replace "U[0-9a-f]{4,}" s (hex-str-to-unicode-char $0) 1))
</code></pre>

<p>So now I can type "U" followed by 4 hexadecimal characters, and the appropriate Unicode character is inserted automatically: "U f80a" is converted to "". (I had to insert a space after the U to prevent translation.)</p>

<p>You can happily use Unicode characters anywhere in newLISP code, if your text editor or console is up to the job. And if <em>ustring</em> is available, you can generate them easily too:</p>

<pre><code>(constant (sym (ustring "U 2660")) 4  ; spades
       (sym (ustring "U 2661"))      3  ; hearts
       (sym (ustring "U 2662"))      2  ; diamonds
       (sym (ustring "U 2663"))      1  ; clubs
     )

(symbols)

(! != $ $0 $1 $10 $11 $12 $13 $14 $15 $2 $3 $4 $5 $6 $7 $8 $9 $HOME $args $idx $main-args ...  zero? | ~ ♠ ♡ ♢ ♣)

(println "(&gt; ♢ ♣)? " (&gt; ♢ ♣))
(&gt; ♢ ♣)? true

(println "(&gt; ♡ ♠)? " (&gt; ♡ ♠))
(&gt; ♡ ♠)? nil
</code></pre>

<p>Using descriptive Unicode characters for your symbol names could introduce a whole new level of readability to your code!</p>

<pre><code>(constant (global '☼)  MAIN)
(context '☺)

(define (☻ ✄ ☁ ⍾)
   (print ✄ ☁ ⍾))

(define (‽) 
   (println {‽}))

(context ☼)
(set '℥ "what "  'ᴥ "the " 'ᴒ "dickens")
(☺:☻ ℥ ᴥ ᴒ)
(☺:‽)
</code></pre>

<p>Appropriately enough, that last function call returns "‽", which is the much-needed <a href="http://en.wikipedia.org/wiki/Interrobang">interrobang</a> character.</p>

<p>The problem now is to remember all those four digit hexadecimal numbers that identify the Unicode characters. I whipped up a quick Unicode browser in newLISP:</p>

<p><img src="data/images/unicode-app.png" alt="a Unicode browser" title="" /></p>

<p>This just shows a page of Unicode characters at a time, and lets you move up and down through the 'pages'. It has some problems when the character code exceeds FFFF - I don't know why‽</p>

<p>This post should display correctly on most modern browsers. If you see lots of boxes rather than characters, then you are using a browser or system that doesn't handle Unicode well. This applies to  the iPhone and iPod Touch as well: it appears that Mobile Safari doesn't like Unicode as much as its desktop version. Apple - improve Unicode support please!</p
        
]]></content>
  </entry>


<entry>
   <title>googled again </title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/googledagain" /> 
   <id>http://unbalanced-parentheses.nfshost.com/googledagain</id> 
   <published>2008-07-13T18:33:53Z</published>
   <updated>2008-07-13T18:33:53Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>In the top right corner of this page you'll see a search box. This is a custom Google search engine, and it's currently set to search three newLISP-related sites using Google technology:  <a href="unbalanced-parentheses.nfshost.com">this one</a>, the main newLISP site at <a href="http://newlisp.org">newlisp.org</a>, and the <a href="http://newlisp-on-noodles.org/wiki/index.php/NewLISP_on_Noodles">newLISP on Noodles wiki</a>. I didn't want to add anyone else's site without their permission or knowledge, but it's easy to add extra sites, so just let me know if you'd like yours added.</p>

<p>So far I've found it fairly useful, and it's meant that I haven't had to write my own blog search tool yet. However, it's been doing odd things with the HTML display of the page, generating thousands of Javascript errors and doing weird stuff like (apparently) loading the page more than once. Also, it fails to find things that I think it should, so I'm not convinced it's as good as Google engineers apparently think it is.</p>

<p>If anyone is at all knowledgeable about what the custom Google search engine is doing with its HTML, please help! The Google engineers can't be bothered to help anyone use their work <a href="http://groups.google.com/group/google-custom-search-creating-and-editing/topics">it seems</a>, so I'm on my own. Perhaps I'll have to write my own search engine after all...!</p>
        
]]></content>
  </entry>


<entry>
   <title>(newLISP) plist</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/newlispplist" /> 
   <id>http://unbalanced-parentheses.nfshost.com/newlispplist</id> 
   <published>2008-06-23T16:00:45Z</published>
   <updated>2008-06-23T16:00:45Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>Seth Dillingham is a unusual guy. As well as - apparently - being able to think in regular expressions, he is also prepared to write something useful for us newLISPers, even though he doesn't use the language himself. If you use BBEdit or TextWrangler, and use newLISP, you'll probably want to get the latest version of his <a href="http://media.macrobyte.net/bbedit/newlisp.plist.zip">codeless language module</a> for newLISP, which he's updated for the forthcoming (and amazing) newLISP version 9.4.</p>

<p>You can also read about how it's done, too, <a href="http://www.truerwords.net/articles/bbedit/codeless_language_module.html">here</a>. </p>

<p>Thanks, Seth, and good luck with the <a href="http://www.pmc.org/">PMC challenge</a>!</p>

<br />
<p><a href="http://www.truerwords.net/fundraising/pmcsoftware/"><img
  src="http://media.truerwords.net/images/pmc/donations_wanted_2008_500.png"
  width="500" height="331"alt="Donate Software, Fight Cancer" /></a></p>
        
]]></content>
  </entry>


<entry>
   <title>C*mments</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/cmments" /> 
   <id>http://unbalanced-parentheses.nfshost.com/cmments</id> 
   <published>2008-06-07T09:20:02Z</published>
   <updated>2008-06-07T09:20:02Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>I've managed to cobble together a Comments plugin for this site. It's still a work in progress, so I don't expect it to be 100% reliable just yet. If you submit a comment and it doesn't appear (and you don't consider yourself to be a spammer), please email me and I'll investigate!</p>

<p>I was a bit surprised that, after installing the plugin, it took only 25 minutes for the first spammers to arrive and leave their tell-tale pharmacological trail. Google doesn't bother much with this site, but apparently spammers can immediately find any web page with a comments form - presumably they're searching the internet for anything with the word "comments" in? Perhaps I should have called it something different.</p>

<p>As it turned out, it wasn't too bad, because it gave me the chance to test some IP-blacklisting code I put together. This may or may not work, but I needed a bit of genuine spam to test against. I don't need any more, though. :)</p>

<p>I'm trying out a JavaScript utility called <a href="http://wmd-editor.com/">WMD</a>. This lets you format your comments in Markdown and see what the results look like before they're submitted. Although there's a development version of Markdown written in newLISP <a href="http://unbalanced-parentheses.nfshost.com/downloads/">here</a>, I couldn't use this to generate a live preview in a web page - JavaScript still rules the browser.</p>
        
]]></content>
  </entry>


<entry>
   <title>Comment on cmments from cormullion</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/cmments" /> 
   <id>http://unbalanced-parentheses.nfshost.com/cmments2008-06-14T08:57:24Z</id>
   <author>
     <name>cormullion</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>
   <published>2008-06-14T08:57:24Z</published>
   <updated>2008-06-14T08:57:24Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>this is a comment to test the spam scoring system</p>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>Comment on cmments from newlisper</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/cmments" /> 
   <id>http://unbalanced-parentheses.nfshost.com/cmments2008-06-14T22:09:25Z</id>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>
   <published>2008-06-14T22:09:25Z</published>
   <updated>2008-06-14T22:09:25Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>this is a comment to test the Bayesian spam scoring system</p>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>The making of ... Scene 78</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/themakingofscene78" /> 
   <id>http://unbalanced-parentheses.nfshost.com/themakingofscene78</id> 
   <published>2008-05-27T13:19:29Z</published>
   <updated>2008-05-27T13:19:29Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>INT. OFFICE. NIGHT. GEORGE sits at a big desk. A computer screen casts a dull light over a pile of papers.</p>

<p>The phone rings. GEORGE answers.</p>

<p><strong>STEVE: (VOICEOVER)</strong> Hey, George, it's Steve. Any progress on the title? Gonna have to move forward on this real quick now.</p>

<p><strong>GEORGE:</strong> Nothing yet, Steve. Still working through some suggestions. I got the final draft of the titlemaker code, just running it now.</p>

<p><strong>STEVE:</strong> Uh huh, OK. What did you feed into it this time?</p>

<p><strong>GEORGE:</strong> Those key words we talked about last week. Changed a few.</p>

<p><strong>STEVE:</strong> Right. So, did we get any promising ideas?</p>

<p><strong>GEORGE:</strong> Um ... let me see. Bit of problem with memory allocation. Ah yes. How about: "Indiana Jones and the Lost Kingdom of the Crystal Grail."</p>

<p><strong>STEVE:</strong> I dunno. Sounds a bit ... er ... country and western.</p>

<p><strong>GEORGE:</strong> Know what you mean. So what about "Indiana Jones and the Holy Crystal of the Doom Raiders". OK, don't answer... Try "Indiana Jones and the Doom Skull of the Lost Kingdom"? No? "Indiana Jones and the Lost Legend of the Holy Kingdom"?</p>

<p><strong>STEVE:</strong> Yeah, yeah, it's not ... these are just not working for me. Although I like the first four words. They're, you know, strong. Are you sure that code's good, George?</p>

<p><strong>GEORGE:</strong> Yup, got it from Hanson, out East. He's usually our number one guy for this kind of thing. Looks OK to me, I think we got the latest version...</p>

<p>Cut to computer screen, which shows the following programming code.</p>

<pre><code>(define (mappend) (apply append (apply map (args))))

(define (remove1 elt lst) 
  (let ((elt-pos (find elt lst))) 
    (if elt-pos (pop lst elt-pos)) 
    lst)) 

(define (k-permutations k multiset) 
  (let ((pivots (unique multiset))) 
    (if (= k 1) 
        (map list pivots) 
        (mappend (lambda (p) 
                 (map (lambda (k-1-perm) (cons p k-1-perm)) 
                      (k-permutations (- k 1) (remove1 p multiset)))) 
               pivots)))) 

(set 'keywords 
  '("Lost" "Skull" "Kingdom" "Raiders" "Ark" "Grail" "Doom" "Legend" "Holy" "Crystal" "Kingdom"))

(map (fn (title) 
   (println  "Indiana Jones and the " 
     (title 0) " " 
     (title 1) " of the " 
     (title 2) " " 
     (title 3))) 
   (k-permutations (length keywords) keywords))
</code></pre>

<p><strong>STEVE:</strong> Hmm, well it sure isn't doing the business for us yet. Run it some more - we'll just have to keep at it until something good turns up.</p>

<p><strong>GEORGE:</strong> OK, Steve. What about "Indiana Jones and the Lost Skull of the Legend Kingdom"?</p>

<p><strong>STEVE:</strong> Nah.</p>

<p><strong>GEORGE:</strong> Uh, "Indiana Jones and the Grail Ark of the Holy Skull"?</p>

<p><strong>STEVE:</strong> Holy skull? Christ, George, I think even Crystal Gayle's better than that.</p>

<p>FADE.</p
        
]]></content>
  </entry>


<entry>
   <title>Comment on themakingofscene78 from newlisper</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/themakingofscene78" /> 
   <id>http://unbalanced-parentheses.nfshost.com/themakingofscene782008-06-04T18:50:36Z</id>
   <author>
     <name>newlisper</name>
     <uri></uri>
   </author>
   <published>2008-06-04T18:50:36Z</published>
   <updated>2008-06-04T18:50:36Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>That code is wrong, in fact. I'll post the correct code later this week</p>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>Comment on themakingofscene78 from newlisper</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/themakingofscene78" /> 
   <id>http://unbalanced-parentheses.nfshost.com/themakingofscene782008-06-06T17:08:34Z</id>
   <author>
     <name>newlisper</name>
     <uri></uri>
   </author>
   <published>2008-06-06T17:08:34Z</published>
   <updated>2008-06-06T17:08:34Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <pre><code>
(define (make-k-permutations k multiset) 
  (let ((pivots (unique multiset))) 
    (if (= k 1) 
        (map list pivots) 
        (let ((acc '())) 
          (dolist (p pivots) 
            (let ((sub-multiset (remove1 p multiset))) 
              (dolist (sub-perm 
                       (make-k-permutations (- k 1) sub-multiset)) 
                (push (cons p sub-perm) acc)))) 
          acc)))) 

(define (remove1 elt lst) 
  (let ((elt-pos (find elt lst))) 
    (if elt-pos (pop lst elt-pos)) 
    lst)) 
</code></pre>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>Comment on themakingofscene78 from newlisper</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/themakingofscene78" /> 
   <id>http://unbalanced-parentheses.nfshost.com/themakingofscene782008-06-06T17:18:15Z</id>
   <author>
     <name>newlisper</name>
     <uri></uri>
   </author>
   <published>2008-06-06T17:18:15Z</published>
   <updated>2008-06-06T17:18:15Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>That code above is RIck Hanson's code for finding all permutations of a list.</p>

<p>Cheers Rick!</p>


        
]]>
  </content>
</entry>

  
  
<entry>
   <title>Comment on themakingofscene78 from newlisper</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/themakingofscene78" /> 
   <id>http://unbalanced-parentheses.nfshost.com/themakingofscene782008-06-07T07:29:58Z</id>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>
   <published>2008-06-07T07:29:58Z</published>
   <updated>2008-06-07T07:29:58Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>testing Markdown formatting:</p>

<pre><code>(code)
</code></pre>

<ul>
<li>list</li>
<li>list</li>
<li>list</li>
</ul>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>Vacuum-tube Lisp</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/vacuumtubelisp" /> 
   <id>http://unbalanced-parentheses.nfshost.com/vacuumtubelisp</id> 
   <published>2008-05-25T08:51:24Z</published>
   <updated>2008-05-25T08:51:24Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>I love the idea of a <a href="http://infolab.stanford.edu/pub/voy/museum/pictures/display/2-2-Tubes.htm">vacuum-tube computer</a> running Lisp. Here's <a href="http://www.iwriteiam.nl/HaCAR_CDR.html">Steve Russell</a>:</p>

<blockquote>
<p>I wrote the first implementation of a LISP interpreter on the IBM 704 at MIT in early in 1959.</p>

<p>The 704 family (704, 709, 7090) had "Address" and "Decrement" fields that were 15 bits long in some of the looping instructions. There were also special load and store instructions that moved these 15-bit addresses between memory and the index regiseters ( 3 on the 704, 7 on the others )</p>

<p>We had devised a representation for list structure that took advantage of these instructions.</p>

<p>Because of an unfortunate temporary lapse of inspiration, we couldn't think of any other names for the 2 pointers in a list node than "address" and "decrement", so we called the functions CAR for "Contents of Address of Register" and CDR for "Contents of Decrement of Register".</p>

<p>After several months and giving a few classes in LISP, we realized that "first" and "rest" were better names, and we (John McCarthy, I and some of the rest of the AI Project) tried to get people to use them instead.</p>

<p>Alas, it was too late! We couldn't make it stick at all. So we have CAR and CDR.</p>
</blockquote>

<p>Like Steve, I much prefer <em>first</em> and <em>rest</em> to <em>car</em> and <em>cdr</em>. This approach is evident throughout newLISP, which usually leans towards a user-friendly and abbreviation-free approach to function naming.</p>

<p>But, although <em>car</em> and <em>cdr</em> have been uninspired for nearly 50 years, they have survived because they offer an extra geeky ability: you can add more <em>a</em> and <em>d</em> letters between the "c" and "r", to produce functions with even weirder names. So <em>caddr</em> finds the <em>car</em> of the <em>cdr</em> of the <em>cdr</em>; you read from left to right, although the functions are applied from right to left as usual.</p>

<p>To be honest, I don't know how I've managed to write any code at all in newLISP without having this readable and user-friendly syntax at my fingertips. So it's time for newLISP to be 'cdadderized':</p>

<pre><code>(define (car x) (first x))
(define (cdr x) (rest x))

(define (cdadderize x) 
  (inc 'x)
  (set 'results '())
  (until (= x 0)
     (push   (% x 2) results)
     (set 'x (/ x 2)))
  (set 'results (rest results) 'f-name results)
  (map (fn (a b) (replace a results b)) '(0 1) '("(car " "(cdr "))
  (push (string "x"  (dup ")" (length results))) results -1)
  (set 'results (join results))
  (map (fn (a b) (replace a f-name b)) '(0 1) '("a" "d"))
  (letex ((fnm   (sym (string "c" (join f-name) "r")))
          (body results))
    (define (fnm x) (eval-string body))
    fnm))

(for (i 3 1022) (cdadderize i)) ; we did 1 and 2 :)
</code></pre>

<p>Not the prettiest code, but let's run it and look at the new functions that have been defined:</p>

<pre><code>(filter (fn (s) 
    (and (starts-with  (name s) "ca|cd" 0) 
         (ends-with (name s) "r"))) 
    (symbols))
;-&gt;
(caaaaaaaaaar caaaaaaaaadr caaaaaaaaar caaaaaaaadr caaaaaaaar caaaaaaadar caaaaaaaddr 
caaaaaaadr caaaaaaar caaaaaadaar caaaaaadadr caaaaaadar caaaaaaddar caaaaaadddr 
caaaaaaddr caaaaaadr caaaaaar caaaaadaaar caaaaadaadr caaaaadaar caaaaadadar caaaaadaddr 
caaaaadadr caaaaadar caaaaaddaar caaaaaddadr caaaaaddar caaaaadddar caaaaaddddr 
caaaaadddr caaaaaddr caaaaadr caaaaar caaaadaaaar caaaadaaadr caaaadaaar caaaadaadar 
caaaadaaddr caaaadaadr caaaadaar caaaadadaar caaaadadadr caaaadadar caaaadaddar 
caaaadadddr caaaadaddr caaaadadr caaaadar caaaaddaaar caaaaddaadr caaaaddaar caaaaddadar 
caaaaddaddr caaaaddadr caaaaddar caaaadddaar caaaadddadr caaaadddar caaaaddddar 
caaaadddddr caaaaddddr caaaadddr caaaaddr caaaadr caaaar caaadaaaaar caaadaaaadr 
caaadaaaar caaadaaadar caaadaaaddr caaadaaadr caaadaaar caaadaadaar caaadaadadr 
caaadaadar caaadaaddar caaadaadddr caaadaaddr caaadaadr caaadaar caaadadaaar caaadadaadr 
caaadadaar caaadadadar caaadadaddr caaadadadr caaadadar caaadaddaar caaadaddadr 
caaadaddar caaadadddar caaadaddddr caaadadddr caaadaddr caaadadr caaadar caaaddaaaar 
caaaddaaadr caaaddaaar caaaddaadar caaaddaaddr caaaddaadr caaaddaar caaaddadaar 
caaaddadadr caaaddadar caaaddaddar caaaddadddr caaaddaddr caaaddadr caaaddar caaadddaaar 
caaadddaadr caaadddaar caaadddadar caaadddaddr caaadddadr caaadddar caaaddddaar 
caaaddddadr caaaddddar caaadddddar caaaddddddr caaadddddr caaaddddr caaadddr caaaddr 
caaadr caaar caadaaaaaar caadaaaaadr caadaaaaar caadaaaadar caadaaaaddr caadaaaadr 
caadaaaar caadaaadaar caadaaadadr caadaaadar caadaaaddar caadaaadddr caadaaaddr 
caadaaadr caadaaar caadaadaaar caadaadaadr caadaadaar caadaadadar caadaadaddr caadaadadr 
caadaadar caadaaddaar caadaaddadr caadaaddar caadaadddar caadaaddddr caadaadddr 
caadaaddr caadaadr caadaar caadadaaaar caadadaaadr caadadaaar caadadaadar caadadaaddr 
caadadaadr caadadaar caadadadaar caadadadadr caadadadar caadadaddar caadadadddr 
caadadaddr caadadadr caadadar caadaddaaar caadaddaadr caadaddaar caadaddadar caadaddaddr 
caadaddadr caadaddar caadadddaar caadadddadr caadadddar caadaddddar caadadddddr 
caadaddddr caadadddr caadaddr caadadr caadar caaddaaaaar caaddaaaadr caaddaaaar 
caaddaaadar caaddaaaddr caaddaaadr caaddaaar caaddaadaar caaddaadadr caaddaadar 
caaddaaddar caaddaadddr caaddaaddr caaddaadr caaddaar caaddadaaar caaddadaadr caaddadaar 
caaddadadar caaddadaddr caaddadadr caaddadar caaddaddaar caaddaddadr caaddaddar 
caaddadddar caaddaddddr caaddadddr caaddaddr caaddadr caaddar caadddaaaar caadddaaadr 
caadddaaar caadddaadar caadddaaddr caadddaadr caadddaar caadddadaar caadddadadr 
caadddadar caadddaddar caadddadddr caadddaddr caadddadr caadddar caaddddaaar caaddddaadr 
caaddddaar caaddddadar caaddddaddr caaddddadr caaddddar caadddddaar caadddddadr 
caadddddar caaddddddar caadddddddr caaddddddr caadddddr caaddddr caadddr caaddr 
caadr caar cadaaaaaaar cadaaaaaadr cadaaaaaar cadaaaaadar cadaaaaaddr cadaaaaadr 
cadaaaaar cadaaaadaar cadaaaadadr cadaaaadar cadaaaaddar cadaaaadddr cadaaaaddr 
cadaaaadr cadaaaar cadaaadaaar cadaaadaadr cadaaadaar cadaaadadar cadaaadaddr cadaaadadr 
cadaaadar cadaaaddaar cadaaaddadr cadaaaddar cadaaadddar cadaaaddddr cadaaadddr 
cadaaaddr cadaaadr cadaaar cadaadaaaar cadaadaaadr cadaadaaar cadaadaadar cadaadaaddr 
cadaadaadr cadaadaar cadaadadaar cadaadadadr cadaadadar cadaadaddar cadaadadddr 
cadaadaddr cadaadadr cadaadar cadaaddaaar cadaaddaadr cadaaddaar cadaaddadar cadaaddaddr 
cadaaddadr cadaaddar cadaadddaar cadaadddadr cadaadddar cadaaddddar cadaadddddr 
cadaaddddr cadaadddr cadaaddr cadaadr cadaar cadadaaaaar cadadaaaadr cadadaaaar 
cadadaaadar cadadaaaddr cadadaaadr cadadaaar cadadaadaar cadadaadadr cadadaadar 
cadadaaddar cadadaadddr cadadaaddr cadadaadr cadadaar cadadadaaar cadadadaadr cadadadaar 
cadadadadar cadadadaddr cadadadadr cadadadar cadadaddaar cadadaddadr cadadaddar 
cadadadddar cadadaddddr cadadadddr cadadaddr cadadadr cadadar cadaddaaaar cadaddaaadr 
cadaddaaar cadaddaadar cadaddaaddr cadaddaadr cadaddaar cadaddadaar cadaddadadr 
cadaddadar cadaddaddar cadaddadddr cadaddaddr cadaddadr cadaddar cadadddaaar cadadddaadr 
cadadddaar cadadddadar cadadddaddr cadadddadr cadadddar cadaddddaar cadaddddadr 
cadaddddar cadadddddar cadaddddddr cadadddddr cadaddddr cadadddr cadaddr cadadr 
cadar caddaaaaaar caddaaaaadr caddaaaaar caddaaaadar caddaaaaddr caddaaaadr caddaaaar 
caddaaadaar caddaaadadr caddaaadar caddaaaddar caddaaadddr caddaaaddr caddaaadr 
caddaaar caddaadaaar caddaadaadr caddaadaar caddaadadar caddaadaddr caddaadadr caddaadar 
caddaaddaar caddaaddadr caddaaddar caddaadddar caddaaddddr caddaadddr caddaaddr 
caddaadr caddaar caddadaaaar caddadaaadr caddadaaar caddadaadar caddadaaddr caddadaadr 
caddadaar caddadadaar caddadadadr caddadadar caddadaddar caddadadddr caddadaddr 
caddadadr caddadar caddaddaaar caddaddaadr caddaddaar caddaddadar caddaddaddr caddaddadr 
caddaddar caddadddaar caddadddadr caddadddar caddaddddar caddadddddr caddaddddr 
caddadddr caddaddr caddadr caddar cadddaaaaar cadddaaaadr cadddaaaar cadddaaadar 
cadddaaaddr cadddaaadr cadddaaar cadddaadaar cadddaadadr cadddaadar cadddaaddar 
cadddaadddr cadddaaddr cadddaadr cadddaar cadddadaaar cadddadaadr cadddadaar cadddadadar 
cadddadaddr cadddadadr cadddadar cadddaddaar cadddaddadr cadddaddar cadddadddar 
cadddaddddr cadddadddr cadddaddr cadddadr cadddar caddddaaaar caddddaaadr caddddaaar 
caddddaadar caddddaaddr caddddaadr caddddaar caddddadaar caddddadadr caddddadar 
caddddaddar caddddadddr caddddaddr caddddadr caddddar cadddddaaar cadddddaadr cadddddaar 
cadddddadar cadddddaddr cadddddadr cadddddar caddddddaar caddddddadr caddddddar 
cadddddddar cadddddddddr caddddddddr cadddddddr caddddddr cadddddr caddddr cadddr 
caddr cadr car cdaaaaaaaar cdaaaaaaadr cdaaaaaaar cdaaaaaadar cdaaaaaaddr cdaaaaaadr 
cdaaaaaar cdaaaaadaar cdaaaaadadr cdaaaaadar cdaaaaaddar cdaaaaadddr cdaaaaaddr 
cdaaaaadr cdaaaaar cdaaaadaaar cdaaaadaadr cdaaaadaar cdaaaadadar cdaaaadaddr cdaaaadadr 
cdaaaadar cdaaaaddaar cdaaaaddadr cdaaaaddar cdaaaadddar cdaaaaddddr cdaaaadddr 
cdaaaaddr cdaaaadr cdaaaar cdaaadaaaar cdaaadaaadr cdaaadaaar cdaaadaadar cdaaadaaddr 
cdaaadaadr cdaaadaar cdaaadadaar cdaaadadadr cdaaadadar cdaaadaddar cdaaadadddr 
cdaaadaddr cdaaadadr cdaaadar cdaaaddaaar cdaaaddaadr cdaaaddaar cdaaaddadar cdaaaddaddr 
cdaaaddadr cdaaaddar cdaaadddaar cdaaadddadr cdaaadddar cdaaaddddar cdaaadddddr 
cdaaaddddr cdaaadddr cdaaaddr cdaaadr cdaaar cdaadaaaaar cdaadaaaadr cdaadaaaar 
cdaadaaadar cdaadaaaddr cdaadaaadr cdaadaaar cdaadaadaar cdaadaadadr cdaadaadar 
cdaadaaddar cdaadaadddr cdaadaaddr cdaadaadr cdaadaar cdaadadaaar cdaadadaadr cdaadadaar 
cdaadadadar cdaadadaddr cdaadadadr cdaadadar cdaadaddaar cdaadaddadr cdaadaddar 
cdaadadddar cdaadaddddr cdaadadddr cdaadaddr cdaadadr cdaadar cdaaddaaaar cdaaddaaadr 
cdaaddaaar cdaaddaadar cdaaddaaddr cdaaddaadr cdaaddaar cdaaddadaar cdaaddadadr 
cdaaddadar cdaaddaddar cdaaddadddr cdaaddaddr cdaaddadr cdaaddar cdaadddaaar cdaadddaadr 
cdaadddaar cdaadddadar cdaadddaddr cdaadddadr cdaadddar cdaaddddaar cdaaddddadr 
cdaaddddar cdaadddddar cdaaddddddr cdaadddddr cdaaddddr cdaadddr cdaaddr cdaadr 
cdaar cdadaaaaaar cdadaaaaadr cdadaaaaar cdadaaaadar cdadaaaaddr cdadaaaadr cdadaaaar 
cdadaaadaar cdadaaadadr cdadaaadar cdadaaaddar cdadaaadddr cdadaaaddr cdadaaadr 
cdadaaar cdadaadaaar cdadaadaadr cdadaadaar cdadaadadar cdadaadaddr cdadaadadr cdadaadar 
cdadaaddaar cdadaaddadr cdadaaddar cdadaadddar cdadaaddddr cdadaadddr cdadaaddr 
cdadaadr cdadaar cdadadaaaar cdadadaaadr cdadadaaar cdadadaadar cdadadaaddr cdadadaadr 
cdadadaar cdadadadaar cdadadadadr cdadadadar cdadadaddar cdadadadddr cdadadaddr 
cdadadadr cdadadar cdadaddaaar cdadaddaadr cdadaddaar cdadaddadar cdadaddaddr cdadaddadr 
cdadaddar cdadadddaar cdadadddadr cdadadddar cdadaddddar cdadadddddr cdadaddddr 
cdadadddr cdadaddr cdadadr cdadar cdaddaaaaar cdaddaaaadr cdaddaaaar cdaddaaadar 
cdaddaaaddr cdaddaaadr cdaddaaar cdaddaadaar cdaddaadadr cdaddaadar cdaddaaddar 
cdaddaadddr cdaddaaddr cdaddaadr cdaddaar cdaddadaaar cdaddadaadr cdaddadaar cdaddadadar 
cdaddadaddr cdaddadadr cdaddadar cdaddaddaar cdaddaddadr cdaddaddar cdaddadddar 
cdaddaddddr cdaddadddr cdaddaddr cdaddadr cdaddar cdadddaaaar cdadddaaadr cdadddaaar 
cdadddaadar cdadddaaddr cdadddaadr cdadddaar cdadddadaar cdadddadadr cdadddadar 
cdadddaddar cdadddadddr cdadddaddr cdadddadr cdadddar cdaddddaaar cdaddddaadr cdaddddaar 
cdaddddadar cdaddddaddr cdaddddadr cdaddddar cdadddddaar cdadddddadr cdadddddar 
cdaddddddar cdadddddddr cdaddddddr cdadddddr cdaddddr cdadddr cdaddr cdaderizer 
cdadr cdar cddaaaaaaar cddaaaaaadr cddaaaaaar cddaaaaadar cddaaaaaddr cddaaaaadr 
cddaaaaar cddaaaadaar cddaaaadadr cddaaaadar cddaaaaddar cddaaaadddr cddaaaaddr 
cddaaaadr cddaaaar cddaaadaaar cddaaadaadr cddaaadaar cddaaadadar cddaaadaddr cddaaadadr 
cddaaadar cddaaaddaar cddaaaddadr cddaaaddar cddaaadddar cddaaaddddr cddaaadddr 
cddaaaddr cddaaadr cddaaar cddaadaaaar cddaadaaadr cddaadaaar cddaadaadar cddaadaaddr 
cddaadaadr cddaadaar cddaadadaar cddaadadadr cddaadadar cddaadaddar cddaadadddr 
cddaadaddr cddaadadr cddaadar cddaaddaaar cddaaddaadr cddaaddaar cddaaddadar cddaaddaddr 
cddaaddadr cddaaddar cddaadddaar cddaadddadr cddaadddar cddaaddddar cddaadddddr 
cddaaddddr cddaadddr cddaaddr cddaadr cddaar cddadaaaaar cddadaaaadr cddadaaaar 
cddadaaadar cddadaaaddr cddadaaadr cddadaaar cddadaadaar cddadaadadr cddadaadar 
cddadaaddar cddadaadddr cddadaaddr cddadaadr cddadaar cddadadaaar cddadadaadr cddadadaar 
cddadadadar cddadadaddr cddadadadr cddadadar cddadaddaar cddadaddadr cddadaddar 
cddadadddar cddadaddddr cddadadddr cddadaddr cddadadr cddadar cddaddaaaar cddaddaaadr 
cddaddaaar cddaddaadar cddaddaaddr cddaddaadr cddaddaar cddaddadaar cddaddadadr 
cddaddadar cddaddaddar cddaddadddr cddaddaddr cddaddadr cddaddar cddadddaaar cddadddaadr 
cddadddaar cddadddadar cddadddaddr cddadddadr cddadddar cddaddddaar cddaddddadr 
cddaddddar cddadddddar cddaddddddr cddadddddr cddaddddr cddadddr cddaddr cddadr 
cddar cdddaaaaaar cdddaaaaadr cdddaaaaar cdddaaaadar cdddaaaaddr cdddaaaadr cdddaaaar 
cdddaaadaar cdddaaadadr cdddaaadar cdddaaaddar cdddaaadddr cdddaaaddr cdddaaadr 
cdddaaar cdddaadaaar cdddaadaadr cdddaadaar cdddaadadar cdddaadaddr cdddaadadr cdddaadar 
cdddaaddaar cdddaaddadr cdddaaddar cdddaadddar cdddaaddddr cdddaadddr cdddaaddr 
cdddaadr cdddaar cdddadaaaar cdddadaaadr cdddadaaar cdddadaadar cdddadaaddr cdddadaadr 
cdddadaar cdddadadaar cdddadadadr cdddadadar cdddadaddar cdddadadddr cdddadaddr 
cdddadadr cdddadar cdddaddaaar cdddaddaadr cdddaddaar cdddaddadar cdddaddaddr cdddaddadr 
cdddaddar cdddadddaar cdddadddadr cdddadddar cdddaddddar cdddadddddr cdddaddddr 
cdddadddr cdddaddr cdddadr cdddar cddddaaaaar cddddaaaadr cddddaaaar cddddaaadar 
cddddaaaddr cddddaaadr cddddaaar cddddaadaar cddddaadadr cddddaadar cddddaaddar 
cddddaadddr cddddaaddr cddddaadr cddddaar cddddadaaar cddddadaadr cddddadaar cddddadadar 
cddddadaddr cddddadadr cddddadar cddddaddaar cddddaddadr cddddaddar cddddadddar 
cddddaddddr cddddadddr cddddaddr cddddadr cddddar cdddddaaaar cdddddaaadr cdddddaaar 
cdddddaadar cdddddaaddr cdddddaadr cdddddaar cdddddadaar cdddddadadr cdddddadar 
cdddddaddar cdddddadddr cdddddaddr cdddddadr cdddddar cddddddaaar cddddddaadr cddddddaar 
cddddddadar cddddddaddr cddddddadr cddddddar cdddddddaar cdddddddadr cdddddddar 
cddddddddar cdddddddddr cddddddddr cdddddddr cddddddr cdddddr cddddr cdddr cddr 
cdr)
</code></pre>

<p>Some useful tools there - surely some of these functions would be proud to appear in any Common Lisp program? How about the stretch-limo <em>caaaaaaaaar</em>, for one ("My god, it's full of <em>car</em>s")? Then there's <em>cadadar</em> - north of the USA, if you have a cold. A few are useful in other ways, too: <em>cdddddddddr</em> provides excellent tonguing practice for woodwind players, especially the bassoonists among you.</p>

<p>By the way, for compatibility with Common Lisp, it's not necessary to go all the way up 1022. Call <em>(cdadderize 14)</em> to give you:</p>

<pre><code>(caaar caadr caar cadar caddr cadr car cdaar cdadr cdar cddar cdddr cddr cdr)
</code></pre>

<p>whereas 30 gives you everything up to <em>cddddr</em>.</p>

<p>To be honest, I can't see myself using these very much. Well, OK: I will <em>never</em> use these. But I like the idea that the ever-adaptable Lisp was once written for vacuum-tubes and can still run like the wind on my iMac.</p>
        
]]></content>
  </entry>


<entry>
   <title>Comment on vacuumtubelisp from newlisper</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/vacuumtubelisp" /> 
   <id>http://unbalanced-parentheses.nfshost.com/vacuumtubelisp2008-06-06T17:28:07Z</id>
   <author>
     <name>newlisper</name>
     <uri>newlisper</uri>
   </author>
   <published>2008-06-06T17:28:07Z</published>
   <updated>2008-06-06T17:28:07Z</updated>
   <content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        <p>abracdadr!</p>
        
]]>
  </content>
</entry>

  
  
<entry>
   <title>iTunes covers by newLISP</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/itunescoversbynewlisp" /> 
   <id>http://unbalanced-parentheses.nfshost.com/itunescoversbynewlisp</id> 
   <published>2008-05-20T21:31:19Z</published>
   <updated>2008-05-20T21:31:19Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>The latest iPods and iPhones from Apple share an excellent user interface, but there's one area that I find difficult to use. Ironically, in the case of the iPod at least, it's the main screen you see while music's being played that's the problem. Consider this photograph:</p>

<p><img src="data/images/ipod-display.jpg" alt="photo of iPod Touch being unhelpful" title="this is what my iPod sometimes looks like" /></p>

<p>It gives a reasonable impression of what the problems are. Unless your eyesight is good (mine isn't), and the lighting conditions are good (they often aren't), it's hard to read the three lines of text at the top - artist, title, and album. Two of these lines are drawn in grey on a black background. A lower-case 'a' in the chosen font measures just over 1 millimetre, or about 3 points. The large area in the middle of the display can show you the album artwork, but if there's no artwork you see two big quavers on a light grey background. What really needs to be provided is a customizable display, where you can specify what information is shown, and how it's presented. It would be nice if you could ask for a display that contains the main information in a larger font, and easier to read graphics.</p>

<p>But, I hear you say, what's all this got to do with newLISP?</p>

<p>You know the answer.</p>

<p>I couldn't resist trying to persuade iTunes to create substitute album artwork that shows the music's details in  larger type as album art when it's downloaded to the iPod... I can use newLISP for most of the work. But, unfortunately, the easiest way to talk to iTunes on MacOS X is by using AppleScript, that quirky and devious language whose syntax was once described as "similar to English spelling - not thoroughly thought through".</p>

<p>So let's get the AppleScript stuff over first. Here's a good place to start: get the current selection from iTunes. The necessary AppleScript can be wrapped up in a newLISP function call:</p>

<pre><code>(define (itunes-get-selection)
    (let ((result (exec 
             (format [text]osascript -s s -e 'tell application "iTunes" to get selection'[/text]))))
         (set 'result (replace "{|}" (first result) "" 0))
         (parse result ", ")))
</code></pre>

<p>iTunes returns the information in an AppleScript list, which is easily changed into a newLISP list. Notice that extra '-s s' option flag in the osascript command. That appears to be significant. The result is a list of wordy track references (WTRs):</p>

<pre><code>("file track id 15639 of user playlist id 13999 of source id 41 of application \"iTunes\"" 
 "file track id 15299 of user playlist id 13999 of source id 41 of application \"iTunes\"")
</code></pre>

<p>Given a WTR, it's possible to ask iTunes for more information about a track. As usual, I use the Unlikely Delimiter Ploy (UDP) when obtaining information from iTunes, mainly because iTunes track names can contain virtually any character. I've not yet seen four tildes used before, though, so I'm sticking with them for now:</p>

<pre><code>(define (itunes-get-details-of-track file-track-id)
  (let ((result (exec 
            (format [text]osascript -s s -e 'tell application "iTunes"
              tell %s 
                set d to (name &amp; "~~~~" &amp; artist &amp; "~~~~" &amp; album &amp; "~~~~" &amp; duration &amp; "~~~~" &amp; year &amp; "~~~~" &amp; genre) as text
               end tell
             end tell '[/text] file-track-id))))
      (when result           
         (set 'result 
             (transpose 
                (list '(track-name artist album duration year genre) 
                (parse (trim (first result) {"} {"}) "~~~~"))))
          result)))
</code></pre>

<p>That's such an ugly function! But it works:</p>

<pre><code>((track-name "Maiden Voyage") 
 (artist "Herbie Hancock") 
 (album "An Evening With Herbie Hancock and Chick Corea - In Concert CD2") 
 (duration "810.840026855469") 
 (year "1978") 
 (genre "jazz"))
</code></pre>

<p>There's just one more piece of AppleScript required, to change the album artwork. Apple could have made this nice and easy:</p>

<pre><code>set artwork of track to "some-artwork.jpg" -- this doesn't work :)
</code></pre>

<p>but they didn't. The required newLISP-wrapped code is this:</p>

<pre><code>(define (itunes-set-data-of-artwork file-track-id)
   (exec (format [text]osascript -s s -e 'tell application "iTunes"
      delete every artwork of %s
      set the_artwork to read file (((path to desktop) as text) &amp; "artwork-canvas.pict") from 513 as picture
      set data of artwork 1 of %s to the_artwork
    end tell'[/text] file-track-id file-track-id )))
</code></pre>

<p>This looks for a graphic in PICT format at ~/Desktop/artwork-canvas.pict, strips the 512 byte header, loads the picture data, and applies the result to the track as album artwork.</p>

<p>I can't persuade newLISP-GS to produce PICT files, but luckily the Mac comes with the <em>sips</em> image processing tool, so converting PNG to PICT is easy.</p>

<pre><code>(define (convert-to-pict file-name)
    (let ((new-file-name (replace {(.*)(\.)(.*$)} (string file-name) (string $1 ".pict") 1)))
          (exec (format "sips -s format pict '%s' --out '%s'"  file-name new-file-name))))
</code></pre>

<p>So now I can take off my AppleScripter's hat and switch to newLISP. To produce the graphics, I use a newLISP-GS canvas, after first setting up the graphics system:</p>

<pre><code>(load (append (env "NEWLISPDIR") "/guiserver.lsp"))
(gs:init)
(gs:window 'Artwork 200 200 320 320)  
(gs:canvas 'ArtworkCanvas)
(gs:set-size 'ArtworkCanvas  320 320)
(gs:add-to 'Artwork 'ArtworkCanvas )
(gs:set-background 'ArtworkCanvas gs:gray)
(gs:set-visible 'Artwork true)
</code></pre>

<p>and then use commands such as <em>set-font</em> and <em>draw-text</em> to draw some more informative artwork. The main loop is simple enough, in theory at least:</p>

<pre><code>(dolist (track (itunes-get-selection))
  (set 'data (itunes-get-details-of-track track))

  ; start drawing
  (gs:draw-text 'AlbumText (string (lookup 'artist data)) ...

  ; repeat for other information

  ; then:
  (gs:update)  

  (set 'temp-file (string "/Users/me/Desktop/" {artwork-canvas.png}))
  (gs:export temp-file)
  (convert-to-pict temp-file)
  (itunes-set-data-of-artwork track)

  ; delete all text
  (gs:delete-tag 'AlbumText)

  ; and start on the next one
  )
</code></pre>

<p>In practice there are various issues to address, such as timing - all these external processes appear to hamper a smoothly flowing script - so some <em>sleep</em> commands have to be added. Also, you might want to waste, I mean, spend more time adjusting the formatting and typography. I like adjusting the point size so that the line of type fits perfectly, and changing the colours to suit the genre. But that's another story!</p>

<p><img src="data/images/artwork-canvas.png" alt="some artwork" title="a bit of handmade iTunes artwork" /></p>
        
]]></content>
  </entry>


<entry>
   <title>Two out of three  - TicTacToe</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/twooutofthreetictactoe" /> 
   <id>http://unbalanced-parentheses.nfshost.com/twooutofthreetictactoe</id> 
   <published>2008-05-11T18:35:56Z</published>
   <updated>2008-05-11T18:35:56Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>After a mention of TicTacToe in the newLISP forums, I thought I'd take a look at writing a version of what we used to call Noughts and Crosses for myself. Peter posted a <a href="http://www.turtle.dds.nl/newlisp/tictactoe.lsp">link</a> to his excellent version, which plays a perfect game from the command line. So, to be different, I decided to start from the other end and write a GUI version using newLISP-GS.</p>

<p>There are basically three tasks to do: do the basic game mechanics, implement a user interface, and add a dash or two of intelligent strategy.</p>

<p>The game mechanics are simple enough. You need a board:</p>

<pre><code>(set '*grid* (dup nil 9))
</code></pre>

<p>and a list of winning positions:</p>

<pre><code>(set '*winning-positions* 
   '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6)))
</code></pre>

<p>Each move places a 'X or 'O symbol in the grid, using <em>set-nth</em> or <em>nth-set</em>:</p>

<pre><code>(set-nth (*grid* a-move) 'X)
</code></pre>

<p>There's also a function to find the moves still available:</p>

<pre><code>(define (available-moves)
  (index nil? *grid*))
</code></pre>

<p>and a function to check whether a proposed move is valid:</p>

<pre><code>(define (check-move move)
  (and (&lt;= 0 move 8) (find move (available-moves))))
</code></pre>

<p>Here's a function to see if a player has won:</p>

<pre><code>(define (won? player)
   (letn ((player-squares (index (fn (x) (= x player)) *grid*))
          (wins-for-player 
             (map (fn (win) (= win (intersect win player-squares))) *winning-positions*)))
      (if (exists true? wins-for-player)
          (set '*winner* (list player (find true wins-for-player))))))
</code></pre>

<p>This uses the <em>intersect</em> function, which I haven't used much before. The idea is that the set of grid squares occupied by a player might equal or contain the set of numbers which constitute a winning position:</p>

<pre><code>(set 'win '(2 5 8))
(intersect '(2 5 8) '(2 3 5 7 8))
;-&gt; (2 5 8)
(= win (intersect win '(2 3 5 7 8)))
;-&gt; true
</code></pre>

<p>I wonder if there's a simpler way to see whether '(2 3 5 7 8) contains '(2 5 8)?</p>

<p>Add a <em>game-over?</em> function:</p>

<pre><code>(define (game-over?)
  (or (won? 'X) (won? 'O) (empty? (available-moves))))
</code></pre>

<p>and the mechanics are mostly done.</p>

<p>I found the user interface task a bit harder. The problem is that you have to use an event-driven model, but the only event that's going to happen is the user clicking a square to place a 'X. So inside the main loop:</p>

<pre><code>(do-until (game-over?) (gs:check-event 1000000))
</code></pre>

<p>everything has to be driven by mouse clicks. I ended up with something like this:</p>

<pre><code>(define (do-human-move move)
  (and (not (game-over?) (= *turn* "human"))
       (check-move move)
       (set-nth (*grid* move) 'X)
       (display)
       (set '*turn* "computer")
       (do-computer-move)
       (display)))
</code></pre>

<p>which kind of works - and you can see now why I used <em>set-nth</em>. You might think that <em>nth-set</em> would do the job perfectly, and it does, but it returns the value of the replaced element, which, being nil, finished the <em>and</em> clause too early.</p>

<p>And what about the third task, adding the intelligent strategy? This is certainly the most interesting part of the job, but I haven't had the time to start it yet. I've been testing with the simplest possible strategy:</p>

<pre><code>(define (generate-computer-move)
  (apply amb (available-moves)))
</code></pre>

<p>Here, <em>amb</em> has to be <em>apply</em>ed to a list; unlike <em>randomize</em>, it takes single arguments rather than a single list.</p>

<p>Perhaps one day I'll get round to starting the third task. If you want to help me, get the file from the <a href="http://unbalanced-parentheses.nfshost.com/downloads/">downloads page</a> and get coding!</p>
        
]]></content>
  </entry>


<entry>
   <title>Plug addict</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/plugaddict" /> 
   <id>http://unbalanced-parentheses.nfshost.com/plugaddict</id> 
   <published>2008-05-03T09:54:40Z</published>
   <updated>2008-05-03T09:54:40Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>I'm trying out a very simple plug-in system for the newLISP script (as yet unnamed) that produces this blog. The idea is that you can more easily add or remove features by adding or removing plug-ins, rather than by modifying the main script each time. So far the results are promising.</p>

<p>Each plug-in is just a newLISP context stored in a file, so the first relevant piece of code in the main script is this:</p>

<pre><code>(set 'plug-ins '())
(dolist (i (sort (directory plug-ins-dir "\\.lsp")))
   (load i))
</code></pre>

<p>which loads every newLISP file in the plug-ins directory. The code for a plug-in file looks like this:</p>

<pre><code>(context 'Whatever)
; ... function definitions
; and finally:
(push (context) plug-ins -1)
; eof
</code></pre>

<p>In the last line the plug-in registers its presence and willingness to participate by appending its name to the master list. The advantage of doing it this way is that you can modify the order in which plug-ins load, and execute, by adjusting the file names, rather than by changing any code. For example, given these plug-ins:</p>

<pre><code>01debug.lsp
10html.lsp
20atom.lsp
30cache.lsp
default.lsp
</code></pre>

<p>you can play with the numbers to change the order of execution.</p>

<p>The following macro function in the main script runs through the plug-ins (ie the contexts) in order, executing the same function in each.</p>

<pre><code>(define-macro (call-plug-in-function flag func)
  (catch 
    (dolist (ctxt plug-ins)
      (if (context ctxt func)
          (set 'result (apply (sym func ctxt) (args)))
          (set 'result nil))
      (if (and flag result) 
          (throw result))))
   result)
</code></pre>

<p>This tries to call function <em>func</em> in every available context, in the order the files were loaded. There's a <em>flag</em> argument to the macro which is used to specify whether only one plug-in can handle the task or whether all plug-ins can have a shot at the task. The result returned by each function also determines whether subsequent plug-ins can handle the task if for any reason the current plug-in can't cope.</p>

<p>All that's now required is for the tasks to be organized into functions, and for the functions to be passed to <em>call-plug-in-function</em> for evaluation in all contexts.</p>

<p>Here's an example of how it works, for the Atom news-feed plug-in, given the example set of plug-ins shown above. The main script decides that it's time to choose a template:</p>

<pre><code> (call-plug-in-function true "choose-template")
</code></pre>

<p>The <em>call-plug-in-function</em> macro looks for a <em>choose-template</em> function in every context. Only one template set can be chosen, so the  <em>true</em> value tells all the plug-ins that the first one to handle it successfully will be the only one to handle it. There's no definition for <em>choose-template</em> in the first plug-in (ie <em>Debug:choose-template</em> doesn't exist), but in the next plug-in there is. However, <em>HTML:choose-template</em> decides that it doesn't want to handle anything to do with Atom, so returns nil. Next, it's the turn of <em>Atom:choose-template</em>, which should be able to complete its tasks successfully and return <em>true</em>:</p>

<pre><code>; in context Atom:
(define (choose-template)
  (cond 
     ((= required-format "atom")
         ;
         ; choose suitable template set
         ;
         true)
    (true
         nil)))
</code></pre>

<p>No other plug-ins get the chance of choosing templates now.</p>

<p>Changes to the way Atom-formatted news is generated can be made to the Atom context. The Atom context can be removed altogether without affecting the behaviour of other parts of the application. I could write a different Atom context and try it out by changing the numbers in the filenames.</p>

<p>Notice that I've assumed that the main script provides enough information about the environment and the task in hand for the plug-ins to make intelligent decisions about what to do. I'm also assuming - obviously - that there's no malicious intent or desire to disrupt the whole set-up. It's not a good idea to load any plug-ins from an untrusted source...</p>

<p>It's possible to override built-in behaviour because even the basic tasks are handled by a plug-in file as well. This is loaded last, so it can provide default behaviour to be carried out when none of the other plug-ins have volunteered for tasks.</p>

<p>Some tasks can be handled by a number of different plug-ins one after the other. For example, a 'tidying-up' function is called from the main script with:</p>

<pre><code>(call-plug-in-function nil "tidy-up")
</code></pre>

<p>and each plug-in can do some tidying up if necessary.</p>

<p>It's early days yet, but I'm interested to see how many different tasks I can get the plug-ins to handle until I have to make changes to the main script!</p>
        
]]></content>
  </entry>


<entry>
   <title>Simple help for newLISP</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/simplehelpfornewlisp" /> 
   <id>http://unbalanced-parentheses.nfshost.com/simplehelpfornewlisp</id> 
   <published>2008-04-29T18:04:57Z</published>
   <updated>2008-04-29T18:04:57Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>An interesting <a href="http://www.alh.net/newlisp/phpbb/viewtopic.php?p=12664">discussion</a> about an online help facility for newLISP threw up lots of interesting ideas and useful suggestions. One advantage to not having certain facilities built in is that it gives you scope for making them yourself. This version I threw together is simple enough:</p>

<pre><code>(define (help func-name)
   (if (find func-name "|+*-") (push "\\" func-name))
   (set 'html-text (join (find-all (format {&lt;b&gt;(syntax: \(%s.*?)&lt;/b&gt;} func-name) 
      (read-file "/usr/share/doc/newlisp/newlisp_manual.html")) "\n"))
  (println (replace "&lt;.*?&gt;" html-text "" 0))
  (silent))

&gt; (help "date")
syntax: (date)
syntax: (date int-secs [int-offset])
syntax: (date int-secs int-offset str-format)
syntax: (date-value int-year int-month int-day [int-hour int-min int-sec])
</code></pre>

<p>The first line of the function was a temporary fix for a puzzling bug, and it also offered a nice surprise. The bug was that it was impossible to get help on functions with names like <em>|</em> or <em>+</em> without listing way too much. I eventually realized (duh) that some newLISP symbols were also significant in regular expressions and needed to be escaped. Because no symbols use the period (.), I hadn't bothered to escape it. But it then becomes a useful option for searching for functions:</p>

<pre><code>&gt; (help "fi.")
syntax: (file-info str_name [int-index])
syntax: (file? str-name)
syntax: (filter exp-predicate exp-list)
syntax: (find exp-key list [func-compare | int-option])
syntax: (find str-key str-data [int-option])
syntax: (find-all str-pattern str-text [expr [int-option]])
syntax: (find-all list-pattern list-lists [expr])
syntax: (find-all expr-key list expr func-compare)
syntax: (first list)
syntax: (first array)
syntax: (first str)
</code></pre>

<p>The only thing left to do now is to work out how to avoid using <em>silent</em>. Although I want to suppress the value returned by <em>println</em>, I don't want the prompt to disappear as well. Unfortunately, <em>silent</em> does both. I bet there's a way, though!</p>
        
]]></content>
  </entry>


<entry>
   <title>Dated posts</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/datedposts" /> 
   <id>http://unbalanced-parentheses.nfshost.com/datedposts</id> 
   <published>2008-04-28T22:05:56Z</published>
   <updated>2008-04-28T22:05:56Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>You'll sometimes see the date and time presented in this format - <em>2008-04-19T22:45:33Z</em>. It's the date (year-month-day) followed by a "T", followed by the time (hours:minutes:seconds), followed by a Z, which specifies the Greenwich or UT Time Zone. ('Z' stands for 'Zulu', but that's another, and possibly more interesting, story.) This date-time format conforms to the Atom Date construct, as described in the <a href="http://tools.ietf.org/html/rfc4287#section-3.3">Atom specification</a>:</p>

<blockquote>
<p>A Date construct is an element whose content MUST conform to the
  "date-time" production in RFC3339.  In addition, an uppercase "T"
  character MUST be used to separate date and time, and an uppercase
  "Z" character MUST be present in the absence of a numeric time zone
  offset.</p>

<pre><code>atomDateConstruct =
   atomCommonAttributes,
   xsd:dateTime
</code></pre>

<p>Such date values happen to be compatible with the following
  specifications: ISO.8601.1988, W3C.NOTE-datetime-19980827, and
  W3C.REC-xmlschema-2-20041028.</p>
</blockquote>

<p>and here's <a href="http://www.w3.org/TR/1998/NOTE-datetime-19980827">ISO 8601</a>:</p>

<blockquote>
<p>The following profile of ISO 8601 dates SHOULD be used in
  new protocols on the Internet.  This is specified using the syntax
  description notation defined in ABNF.</p>
</blockquote>

<pre><code>
     date-fullyear   = 4DIGIT
     date-month      = 2DIGIT  ; 01-12
     date-mday       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on
                               ; month/year
     time-hour       = 2DIGIT  ; 00-23
     time-minute     = 2DIGIT  ; 00-59
     time-second     = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second
                               ; rules
     time-secfrac    = "." 1*DIGIT
     time-numoffset  = ("+" / "-") time-hour ":" time-minute
     time-offset     = "Z" / time-numoffset
    
     partial-time    = time-hour ":" time-minute ":" time-second
                       [time-secfrac]
     full-date       = date-fullyear "-" date-month "-" date-mday
     full-time       = partial-time time-offset
    
     date-time       = full-date "T" full-time
</code></pre>

<p>Important stuff!</p>

<p>In newLISP, you can get time in this format by using a suitable time format string with <em>date</em>. For example, the modification time of a file can be presented in RFC3339 date-time format with this:</p>

<pre><code>(set 'modification-date (date file-mod-date 0 "%Y-%m-%dT%H:%M:%SZ"))
</code></pre>

<p>where <em>file-mod-date</em> is the file's modification date as a seconds-from-1970 value, obtained like this:</p>

<pre><code>(set 'file-mod-date (file-info file 6))
</code></pre>

<p>The previous blogging tool I wrote made extensive use of compressed ISO 8601 identifiers:</p>

<pre><code>20080419224533
</code></pre>

<p>which is a 14-digit number or string. It can be used as either:</p>

<pre><code>(set 'p 20080419224533)
(dec 'p)
;-&gt; 20080419224532
(set 'p "20080419224533")
(length p)
;-&gt; 14
</code></pre>

<p>I used this both as the unique identifier for a post or blog entry, and as the publication date. To convert these compressed 14 digit ISO date-times (and others) to a newLISP seconds-from-1970 value, you can use <em>parse-date</em>:</p>

<pre><code>(parse-date "20080419224533" "%Y%m%d%H%M%S")
;-&gt; 1208645133

(date (parse-date "20080419224533" "%Y%m%d%H%M%S"))
;-&gt; "Sat Apr 19 23:45:33 2008"
</code></pre>

<p>The first problem is that <em>parse-date</em> on MacOS X systems appears to have some flaws. <a href="http://www.alh.net/newlisp/phpbb/viewtopic.php?t=2259">Lutz reckons</a> that libc.dylib on Mac OS X was broken for the  <em>strptime()</em> function somewhere between MacOS X 10.4 (Tiger) and 10.5 (Leopard). It was apparently the case that, for some versions of newLISP and MacOS X, the conversion of compressed ISO8601 identifiers didn't work:</p>

<pre><code>(parse-date "20080411234423" "%Y%m%d%H%M%S") 
;-&gt; nil 
</code></pre>

<p>Suddenly being unable to read date strings without spaces, I spent a few minutes writing a <em>parse-iso-date</em> function:</p>

<pre><code>(define (parse-iso-date s)
 (let ((y (pop s 0 4))
       (m (pop s 0 2))
       (d (pop s 0 2))
       (h (pop s 0 2))
       (mn (pop s 0 2))
       (sec s))
 (parse-date (format "%s %s %s %s %s %s" y m d h mn sec) "%Y %m %d %H %M %S")))
</code></pre>

<p>but it doesn't look like the right solution - just reformatting a string so that it has spaces between the components and then using <em>parse-date</em>. And later I found that I was converting between different date formats too often: from compressed ISO to Atom, or from compressed ISO to a familiar local representation, and then back into Atom again.</p>

<p>When you stare at a problem for long enough, you can often see a bigger problem hidden behind it. I started to dislike seeing these IDs. References to stories used to take the form:</p>

<pre><code>index.cgi?post-id=20080411234423
</code></pre>

<p>which is computer-friendly but user-hostile, easy enough for a computer to produce but not easy for humans to recognise or decipher. I've typed enough of these in by hand to know that it's surprisingly easy to lose your place in a long string of digits when you're tired or in a hurry. Another problem is updating a post makes these date-based IDs less meaningful - but changing them probably isn't the right solution either.</p>

<p>So, for the current blogging script, I've adopted a different approach. Stories are referred to using more readable URLs - I read that this was <a href="http://www.w3.org/Provider/Style/URI">A Good Idea</a>. Dates are now a part of the metadata but extracted and displayed when required, with more emphasis on how old something is rather than the exact moment it was written. And hopefully it's no longer necessary to display weird date formats just because they're used internally by the software.</p>
        
]]></content>
  </entry>


<entry>
   <title>Smashing the Atom</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/smashingtheatom" /> 
   <id>http://unbalanced-parentheses.nfshost.com/smashingtheatom</id> 
   <published>2008-04-19T22:45:33Z</published>
   <updated>2008-04-19T22:45:33Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>Despite my attempts to get the Atom news feed working for this site, it still doesn't work. I'm not clear what the problem is - something to do with the way the page is served, rather than the syntax or the content. I've been hunting on the web for information about whether to serve pages with "Content-Type: application/atom+xml" headers or not, followed by carriage returns or not, without a lot of success.</p>

<p>I'll have a go at fixing it in the next week.</p>

<p>I was quite pleased that the code to produce the Atom document was only about 45 lines, though. </p>

<h3>Edit</h3>

<p>I discovered how to make it work: I used a content type of text/xml:</p>

<pre><code>(set '*content-type* "text/xml\n\n")
</code></pre>

<p>and claimed that I was generating it using a file called 'atom.cgi', although I'm not.</p>

<p>So now I can put this on my page, apparently:</p>

<p><a href="http://feedvalidator.org/check.cgi?url=http%3A//unbalanced-parentheses.nfshost.com/atom.cgi"><img src="data/images/valid-atom.png" alt="[Valid Atom 1.0]" title="Validate my Atom 1.0 feed" /></a></p>

        
]]></content>
  </entry>


<entry>
   <title>Under construction (again)</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/underconstructionagain" /> 
   <id>http://unbalanced-parentheses.nfshost.com/underconstructionagain</id> 
   <published>2008-04-15T10:25:57Z</published>
   <updated>2008-04-15T10:25:57Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        

<p>This site is being rebuilt, again! Yes, I've written another blogging application in newLISP to generate these pages. It's far from finished yet, but at the moment it's looking quite promising: only about 250 lines of newLISP so far, and I hope to get it down even further.</p>

<p>Unfortunately, there are some features I've yet to get round to doing - the most obvious being the Atom newsfeed. Soon, perhaps. </p>

<p>I don't think I'll be enabling comments again, but the email address should be somewhere on this page so pelase write to me!</p>

<p>I've kept the old articles from the earlier blog here, for posterity, even though some of them are no longer applicable - or just plain wrong.</p>
        
]]></content>
  </entry>


<entry>
   <title>Links</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/links" /> 
   <id>http://unbalanced-parentheses.nfshost.com/links</id> 
   <published>2008-03-06T22:44:21Z</published>
   <updated>2008-03-06T22:44:21Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>This post contains a link to <a href="http://adam.schmideg.net/">Adam's newLISP-powered web site</a> (Hi Adam!) and a link to <a href="http://newlisp.wordpress.com/">Alessandro's newLISP blog</a> (Ciao!).</p>

        
]]></content>
  </entry>


<entry>
   <title>Tufte sparklines in newLISP</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/tuftesparklinesinnewlisp" /> 
   <id>http://unbalanced-parentheses.nfshost.com/tuftesparklinesinnewlisp</id> 
   <published>2008-02-28T21:22:26Z</published>
   <updated>2008-02-28T21:22:26Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>That's a weird headline! At least, it is if you're not into infographics. If you are, though, you'll probably already know what I'm going to write about. For the uninitiated, you can read a good introduction at <a href="http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0001OR">Edward Tufte's site</a>.</p>



<p>A sparkline is a little word-sized graph that shows a trend or sequence. Because our brains are so good at reading lower-case words, they also find it easy to absorb data trends if the information is represented in a wavy word-sized graphic - a sparkline. For example, this sparkline <img src="data/images/ub-post-size.png" alt="post size" title="post size" /> shows the changing size of the posts in this blog over time. And this one <img src="data/images/hours-between-posts.png" alt="time between posts" title="time between posts" /> shows the time between each post since I first started in December 2006. Even though I haven't labelled the axes or provided additional information, you can easily pick out a message from the data - if there's a message to pick out. At least, that's the theory behind sparklines. I've been playing around with sparklines for fun, using newLISP. Here are my thoughts so far.</p>



<p>At first I assumed that the best way to draw sparklines would be to generate an SVG sparkline and embed it into the HTML. After all, SVG is a standard vector format using standard XML, and it should display well in all web browsers that follow current standards. Unfortunately, the standards guys have apparently painted themselves into a corner on this one, because XML isn't compatible with HTML (or XHTML) to the extent that you can just put one inside the other. One of the possible solutions is to change the way pages are served to browser clients, so I decided to try another approach.</p>



<p>Another drawback with the automatic generation of graphs from data is that you don't get a chance to play with your graph before publishing it. Sparklines, like anything else, can benefit from a little tweaking to make them look just right.</p>



<p>Here's my first attempt at a rudimentary Sparkline generator running in newLISP-GS:</p>



<p><img src="data/images/sparkline.png" alt="a sparkline generator" title="sparkline" /></p>



<p>At the top, there's the data-entry text box. Anything can be typed in here - non-numeric material is filtered out. This means that you can paste in comma-separated lists as well as plain newLISP-style lists. (This batch of numbers shows the "Coefficients of the '3rd order' mock theta function phi(q)" from the strange and wonderful <a href="http://www.research.att.com/~njas/sequences/Seis.html">On-Line Encyclopedia of Integer Sequences</a>.</p>



<p>Next, there's the sparkline. The width of this sparkline 'canvas' changes according to how much data you input. There is, though, a limit to how much data can be plotted; in a 300 pixel wide window there's room for a 300 element set. That's probably enough for most sparklines. If you want more, you can edit the script to give you a wider window and canvas - but if you do, all the controls will move...</p>



<p>Below is a plethora of sliders ... probably too many. The top one changes the height of the sparkline canvas, so you can squeeze it down to 14 pixels and fit it easily into text. The checkbox at the bottom shows the location of the x-axis.</p>



<p>If you want to play with this code, it's on the downloads page.</p>

        
]]></content>
  </entry>


<entry>
   <title>Googled</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/googled" /> 
   <id>http://unbalanced-parentheses.nfshost.com/googled</id> 
   <published>2008-02-21T16:27:11Z</published>
   <updated>2008-02-21T16:27:11Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>I've moved the Lambdapress project to Google Code. Click on the icon at the bottom right to see the project in its new home. So now you can join in!</p>

<p>Google Code is not the easiest of things to get working - I'm not up on this whole svn/code management thing - but it proposes a few advantages that I'm now starting to appreciate. Recently I spent some time looking for a piece of code that I'd deleted some months ago, and if the project had been in a subversion system like Google Code I could have found it more easily.</p>

<p>I'm also hoping that, one day, googling for 'newLISP' will find some of this web site. Currently I think I've reached page 8 or 9...</p>

        
]]></content>
  </entry>


<entry>
   <title>A newLISP CGI web page in 10 easy steps</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/anewlispcgiwebpagein10easysteps" /> 
   <id>http://unbalanced-parentheses.nfshost.com/anewlispcgiwebpagein10easysteps</id> 
   <published>2008-02-12T19:36:19Z</published>
   <updated>2008-02-12T19:36:19Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>I recently needed an odd sort of calculator. It had to work in multiples of 7.5 and 1.5, and add numbers differently according to the day of the week. I was starting to wonder how I could avoid using a Microsoft Excel spreadsheet to do the job; I'm not a big fan of MicroVBasicSoft or whatever it's called these days. Then I realised that I might be able to do it by writing a newLISP CGI web page instead.</p>

<p>I'm still struggling to understand the basics of CGI and newLISP. Learning CGI isn't that easy when most of the examples are written in Perl. So I thought this would be good way to get some practice. For the purposes of this post, though, I've changed the example to a simple table that adds rows and columns and puts the totals in the last column and bottom row. Let's see if I can describe it in 10 easy steps.</p>

<h2>Step 1: prepare ingredients</h2>

<p>This one <em>is</em> easy:</p>

<pre><code>#!/usr/bin/env newlisp
(load {/usr/share/newlisp/modules/cgi.lsp})
</code></pre>

<p>I want the cgi.lsp module - part of the standard newLISP install - mainly for the <em>CGI:get</em> function, which retrieves values from the incoming form. I've not looked at cgi.lsp much, so I don't know what's in it.</p>

<h2>Step 2: set up a data store</h2>

<p>This step sets up a small data storage area. The data submitted by the user will be loaded into the store for subsequent processing. I use a list of lists rather than an array because:</p>

<ol>
<li><p>Lists are more flexible than arrays, and just as quick if they're not too big.</p></li>
<li><p>Er, that's it, really.</p></li>
</ol>

<pre><code>(set 'rows 10 'columns 10)
(set 'data (dup (dup 0 rows) columns))
</code></pre>

<p>To access the value of the cell at row 3 and column 4, I can use the implicit addressing technique:  (data 3 4).</p>

<h2>Step 3: process the data</h2>

<p>In step 3, I can write the functions that actually do something with the data. When these functions are called, there will be data in the data store.</p>

<pre><code>; get column n of data
(define (column n a-list)
  (map (fn (f) (nth (f n))) a-list))

(define (sum-rows)
    ; in each row, add cells and put value in final cell
    (for (r 0 (- rows 1))
       (nth-set (data r (- columns 1)) (apply add (chop (data r))))))

(define (sum-columns)
    (for (c 0 (- columns 1))
       (nth-set (data (- rows 1) c) (apply add (chop (column c data))))))

(define (class r c)
   (cond 
      ((= c (- columns 1)) "total")
      ((= r (- rows 1)) "total")
      (true "cell")))
</code></pre>

<p>The <em>class</em> function returns a suitable CSS class for a cell given its location. I can use this when building the HTML form to assign different colours to the various input boxes.</p>

<h2>Step 4: extract data from the incoming form </h2>

<p>This step feels like it's in the wrong place. I want to extract data from the incoming form, because it contains the numbers that the user has typed into the input boxes. But what form? What boxes? I haven't created them yet - they won't get created until step 8. Well, I think it's confusing!</p>

<pre><code>; extract data from the form
(for (r 0 (- rows 1))
   (for (c 0 (- columns 1))
      (set 'raw (float (CGI:get (string r c))))
      (if (number? raw)
          (nth-set (data r c) raw))))
</code></pre>

<p>The data store is filled with numbers.       </p>

<h2>Step 5: do the calculation</h2>

<p>If the user clicks the 'Calculate' button to submit the form, a call to <em>CGI:get {recalc}</em> will return true, so the main action part of the script can take place here.</p>

<pre><code>(when (CGI:get {recalc}) (sum-rows) (sum-columns))
</code></pre>

<p>I haven't yet defined that form, though...</p>

<h2>Step 6: tidy up</h2>

<p>Before the data store's contents are displayed, I want to change the zeroes to spaces, purely for aesthetic reasons. I've used the <em>set-ref-all</em> function (new for  version 9.3) to convert them.</p>

<pre><code>(set-ref-all (data 0) "")
</code></pre>

<h2>Step 7: generate HTML, part 1</h2>

<p>The output consists of a header line followed by the HTML page. Most of the HTML is a simple form that uses the POST method to send the completed form to this script.</p>

<pre><code>(print "Content-type: text/html\r\n\r\n")

(print [text]&lt;html&gt;
&lt;head&gt;&lt;title&gt;A newLISP calculator&lt;/title&gt;
&lt;style&gt;#calc .cell {background-color: #ffeeff; }
#calc .total { background-color: #ddffff; }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form id="calc" action="index.cgi" method="POST"&gt;
[/text])

</code></pre>

<h2>Step 8: generate HTML, part 2</h2>

<p>I'm in the middle of the form. Instead of generating the form manually, I've got newLISP to do it for me. Each input box is named after its row and column, and is assigned a class name for styling. There's a simple data-fetch function in it too. newLISP's <em>format</em> function works fine here - originally I used a more complicated template function but this works well.</p>

<pre><code>(for (r 0 (- rows 1))
  (for (c 0 (- columns 1))
    (println (format [text]&lt;input type="text" class="%s" name="%s" size="6" value="%s"&gt;[/text] 
        (class r c) (string r c) (string (data r c))) ))

   ; next row
   (println "<br>\n"))
</code></pre>

<h2>Step 9: generate HTML, part 3</h2>

<p>The form has a 'Calculate' button which sends the 'recalc' message to this script - I dealt with the message in step 5 but this is where the message is defined.</p>

<pre><code>(println
[text]    
    &lt;p&gt;&lt;input type="submit" name="recalc" value="Calculate"&gt;&lt;/p&gt;
    &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
[/text])

(exit)
</code></pre>

<h2>Step 10: Serve hot</h2>

<p>It looks like I made it in 10 steps. To test the script, start up a newLISP web server and point it at the right place. This is what I do on my Mac:</p>

<pre><code>$ sudo newlisp -http -d 80 -w ~/lisp/cgi-test/
</code></pre>

<p>And then visit http://localhost/index.cgi in a browser and try it out. This last step is probably different on other platforms</p>

<p>Any tips or advice from the CGImen or CGIwomen out there will be welcome!</p
        
]]></content>
  </entry>


<entry>
   <title>Hello newLISP 9.3</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/hellonewlisp93" /> 
   <id>http://unbalanced-parentheses.nfshost.com/hellonewlisp93</id> 
   <published>2008-02-09T16:55:46Z</published>
   <updated>2008-02-09T16:55:46Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>This post should have been uploaded some days ago. I've been trying to get round to doing it, but life keeps getting in the way...</p>

<p>The latest version of newLISP, 9.3, is <a href="http://newlisp.org/downloads/">now available</a>, and there are some great new features.</p>

<p>The new <em>when</em> function is going to replace <em>if</em> in a lot of the scripts I've written. I'm sure a lot of newLISP users have made the following mistake at least once:</p>

<pre><code>(if expression
   (action1)
   (action2))
</code></pre>

<p>where they're expecting that both actions will be carried out if the expression is true. But with <em>if</em> it's either the first or the second. The syntax of <em>if</em> requires you to construct a block if you want two or more expressions to be evaluated in sequence:</p>

<pre><code>(if expression
   (begin
      (action1)
      (action2)))
</code></pre>

<p>But now there's <em>when</em>, which will make this form easier to read and write:</p>

<pre><code>(when expression
   (action1)
   (action2))
</code></pre>

<p>There are also many new powerful techniques for processing items in nested lists, including <em>set-ref-all</em>. For a great introduction to these, see Jeff's post at his newly relocated <a href="http://artfulcode.net/articles/working-xml-newlisp/">artful code</a> site.</p>

<p>I haven't managed to prepare a major revision of my <a href="http://www.newlisp.org/index.cgi?Documentation">Introduction to newLISP</a> for this release, but I tried to include examples of most of the new functions I was able to test. It's difficult to keep up with newLISP's pace of development sometimes. But it's much more interesting to describe a moving target than a static one! As each release adds more powerful functions, some of the examples I wrote last year has been rendered obsolete or - in a few cases - inoperative. For example, my example of writing a macro now provides an unnecessary alternative to the built-in <em>when</em> function.</p>

<p>Apparently, *when* was added to the development builds of newLISP is September 2007, but I never noticed it!</p>

<p>Another function that promises to be one of my favourites is <em>find-all</em>. <em>find-all</em> isn't a new function - it used to work on strings - but now it works with lists, and with lists of lists (or association lists). It can also, when working with lists, take action expressions and comparison functions.</p>

<p>First, here's the familiar original form of <em>find-all</em> working on a string:</p>

<pre><code>(set 't {There are 60 seconds in a minute, 60 seconds in an hour, and 24 hours in a day.})
(find-all {\d+} t)
;-&gt; ("60" "60" "24")
</code></pre>

<p>Notice that <em>find-all</em> in this form takes regular expressions without you having to tell it to.</p>

<p>Another form of <em>find-all</em> lets you search a list of lists for a list that matches a pattern. You can specify the pattern with wildcard characters. For example, here's a list of lists:</p>

<pre><code>(set 'symphonies 
  '((Beethoven 9)
    (Haydn 104)
    (Mozart 41)
    (Mahler 10)
    (Wagner 1)
    (Schumann 4)
    (Shostakovich 15)
    (Bruckner 9)))
</code></pre>

<p>To find all the lists that end with 9, use the match pattern '(? 9), where the question mark matches a single item:</p>

<pre><code>(find-all '(? 9) symphonies)
;-&gt; ((Beethoven 9) (Bruckner 9))
</code></pre>

<p>You can also use this form with an 'action expression' at the end, after the list:</p>

<pre><code>(find-all '(? 9) symphonies (println (first $0) { wrote 9 symphonies.}))
Beethoven wrote 9 symphonies.
Bruckner wrote 9 symphonies.
</code></pre>

<p>Here, the action expression uses $0 to refer to each matched element in turn. If you've used <em>replace</em> in newLISP, you'll be familiar with this idea.</p>

<p>There's a third form. For searching a plain list, rather than a list of lists, the syntax is different. Supply four arguments: the search key, the list, an action expression, and the functor, which is the comparison function you want to use for matching the search key. This time, don't use <em>match</em>-style patterns:</p>

<pre><code>(set 'food '("bread" "cheese" "onion" "pickle" "lettuce"))
(find-all "onion" food (print $0 { }) &gt;)
bread cheese lettuce
</code></pre>

<p>Here, <em>find-all</em> is looking for the string "onion" in the list <em>food</em>. It's using the <em>></em> function as a comparison function, so it will find anything that "onion" is greater than. For strings, 'greater than' means appearing later in the default ASCII sorting order, so that "cheese" is greater than "bread" but less than "onion". Notice that, unlike other functions that let you provide comparison functions (namely <em>find</em>, <em>ref</em>, <em>ref-all</em>, <em>ref-set</em>, <em>replace</em> when used with lists, <em>set-ref</em>, <em>set-ref-all</em>, and <em>sort</em>), the comparison function must be supplied. </p>

<p>With the <em>&lt;</em> function, the result is a list of things that "onion" is less than:</p>

<pre><code>(find-all "onion" food (print $0 { }) &lt;)
pickle
</code></pre>

<p>With different comparison functions, and the ability to use an action expression for each 'successful' comparison, you can do quite a lot with a single <em>find-all</em>.</p>

<p>Choose a word:</p>

<pre><code>(set 'word "moonstarer")
</code></pre>

<p>Select a dictionary. On Unix it's probably in /usr/share/dict/words; Windows users can probably find something suitable <a href="http://wordlist.sourceforge.net/">here</a>.</p>

<pre><code>(set 'dictionary (parse (read-file {/usr/share/dict/words})))
</code></pre>

<p>Define a test for the anagram-ness of two words:</p>

<pre><code>(define (anagrams? w1 w2)
  (= (sort (explode w1)) (sort (explode w2))))
</code></pre>

<p>Then use <em>find-all</em> to look for anagrams of the word:</p>

<pre><code>(find-all word dictionary (println $0) anagrams?)

astronomer
</code></pre>

<p>newLISP does all the hard work for you. Notice how the comparison function receives two arguments automatically, one from the list, and the other the contents of *word*. Come to think of it, I don't need to continually explode and sort the first word, do I?. I'll leave you to improve it!</p>

        
]]></content>
  </entry>


<entry>
   <title>Welcome Arc, a new LISP!</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/welcomearcanewlisp" /> 
   <id>http://unbalanced-parentheses.nfshost.com/welcomearcanewlisp</id> 
   <published>2008-01-30T17:55:23Z</published>
   <updated>2008-01-30T17:55:23Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>Congratulations to Paul Graham and Robert Morris on the birth of their new Lisp language, <a href="http://www.arclanguage.com">Arc</a>. It's great to see another new Lisp addition to the family of Lisp. 
I liked these quotes:</p>

<blockquote>
<p>Arc is designed above all for exploratory programming: the kind where you decide what to write by writing it. Exploratory programming is the fun end of programming.</p>

<p>It's not for everyone. In fact, Arc embodies just about every form of political incorrectness possible in a programming language.</p>

<p>It's not a coincidence that we wrote a language for exploratory programming rather than the sort where an army of programmers builds a big, bureaucratic piece of software for a big, bureaucratic organization.</p>
</blockquote>

<p>newLISP encourages experimentation and exploration, and that's made possible by the rich built-in function library, the design of the language, and the involvement of the newLISP community. I built the blogging engine that you're reading now by exploring and trying out ideas, and not being too concerned at first with the theoretical niceties of functional programming. I think that newLISP encourages that approach, as well as allowing for more serious programming. </p>

<p>I suspect that Messrs Graham and Morris would be very happy if people like me - not just Common Lisp initiates - were able to do the same thing with Arc.</p>

<p>Good luck, Arc!</p
        
]]></content>
  </entry>


<entry>
   <title>Lambdalator: the story so far</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/lambdalatorthestorysofar" /> 
   <id>http://unbalanced-parentheses.nfshost.com/lambdalatorthestorysofar</id> 
   <published>2008-01-12T16:20:49Z</published>
   <updated>2008-01-12T16:20:49Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>One of the fun things about my current experiment, the <a href="http://lambdalator.nfshost.com/index.cgi">Lambdalator</a> (a simple script that provides the internet with a 24/7 online newLISP console) is that I left a call to the following function in the script. I'd used this function when I'd first uploaded the script for testing:</p>

<pre><code>
<span class="pr">(</span><span class="p">define</span> <span class="pr">(</span><span class="nl">log-input</span> <span class="nl">x</span><span class="pr">)</span>
    <span class="pr">(</span><span class="p">append-file</span> <span class="nl">log-file-name</span>
        <span class="pr">(</span><span class="p">string</span>
            <span class="pr">(</span><span class="p">date</span>
                <span class="pr">(</span><span class="p">date-value</span><span class="pr">)</span> <span class="i">0</span> <span class="s">"%Y-%m-%d %H:%M:%S"</span><span class="pr">)</span> <span class="s">{ }</span>
            <span class="pr">(</span><span class="nl">get-ip</span><span class="pr">)</span> <span class="s">{ }</span> <span class="nl">x</span> <span class="s">"\n"</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span>

</code></pre>

<p>So whenever anyone types anything and clicks the 'evaluate' button, the date, time, their IP address, and what they typed are saved in a log file. So by looking at the log it's more or less possible to watch people arrive, enter stuff, get annoyed, and go away. This has provided a lot of entertainment - and some education - over the last few weeks, and I'll share some of it here.</p>

<pre><code>2008-01-03 18:40:20 163.453.357.176 hello
</code></pre>

<p>(All IP addresses have been scrambled in this post.)</p>

<p>The big drawback of the Lambdalator is that, as with any programming language, if you don't get the format exactly right, the result will be, at the very least, unexpected. newLISP doesn't pretend to understand English, and the Lambdalator isn't an exercise in artificial intelligence or natural language parsing. It's just a simple online calculator-style utility expecting expressions using newLISP syntax; there's only 100 or so lines of code, and a chunk of that is HTML. </p>

<p>But I wish I'd added some extra code to handle input like this:</p>

<pre><code>2008-01-03 15:06:48 33.453.30.235 how are you doing?
2008-01-03 15:07:14 33.453.30.235 What is the purpose of this?
</code></pre>

<p>or to respond to 'calculations' like this:</p>

<pre><code>2008-01-03 12:08:24 84.43.89.37 Today I am going to work very hard

2008-01-04 21:48:59 93.453.398.228 sausages

2008-01-05 10:08:23 63.453.31.191 poop
</code></pre>

<p>Of the people that have actually tried to use it as a calculator, many have of course been thrown by the postfix notation, the compulsory parentheses, and the need for white space to separate functions and arguments. With no knowledge of what should be typed, and a reluctance to click the 'help' button, newLISP's responses are entertaining, enigmatic, irritating, or just baffling. Here are some examples - I've added the Lambdalator's replies so that you can sympathize - or not - with the questioner:</p>

<pre><code>2008-01-06 22:43:06 83.453.359.133 (+22)
invalid function : (22)

2008-01-05 18:28:54 153.453.38.114 (+2 2)
illegal parameter type : 2

2008-01-04 12:42:33 63.453.381.231 (2 -3 2 2 6)
illegal parameter type : -3

2008-01-06 19:46:23 76.73.453.332 + 2 2
2

2008-01-06 21:11:36 73.453.303.239 61-8
-8

2008-01-05 04:01:22 166.70.39.75 add 5 65 46
46

2008-01-05 02:42:53 33.453.39.213 2*5
nil

2008-01-04 12:41:39 63.453.381.231 4 plus 2
2

2008-01-03 13:28:50 33.453.332.66 cos(x) + sin(y)
invalid function : (x)

2008-01-07 03:56:41 32.423.242.38 ( 6% of 70)
illegal parameter type : %
</code></pre>

<p>Many were confused by the fact that the Lambdalator returns the value of the last expression evaluated, but only the last. So <code>+ 2 2</code> returns the last 2 - not the expected sum. </p>

<p>Here are some optimistic entries, where people have expected more from my efforts than I could deliver:</p>

<pre><code>2008-01-03 15:18:06 143.453.329.143 2x+3=40
nil

2008-01-03 15:18:48 143.453.329.143 x=2y+4
nil

2008-01-05 16:52:29 85.59.94.226 56+33*x=0
nil

2008-01-04 12:39:08 73.453.33.175 x2\y=9
nil

2008-01-03 05:29:36 68.73.453.30 1+x=9
nil
</code></pre>

<p>Luckily newLISP refrains from offering an opinion on such weighty matters. One day I'll write something that solves equations.</p>

<p>Some people have a different idea about what parentheses are:</p>

<pre><code>2008-01-03 18:06:31 68.453.37.26 [2.3]+{4[6.3]}
nil

2008-01-04 13:21:50 193.453.355.48 [ + 2 2 ]
nil
</code></pre>

<p>One problem that I had anticipated is that in newLISP the standard arithmetic operators such as '+' and '-' are integer only, and you use the 'add' and 'sub' equivalents for floating-point operations. I've got used to this, and there's an easy way to re-define '+' to do the job of 'add', but I decided to keep the behaviour as close to the documented default as possible. But it's a pity that a good attempt like the following should have received the wrong answer:</p>

<pre><code>2008-01-08 00:01:49 75.453.32.16 (+ (+ 1.234 91.3) (+ 1.234 91.3))
184
</code></pre>

<p>A few Lisp speakers have visited the site, and they obviously know the basics, although the whole thing is probably much too simplistic and toy-like for the Common Lisp folks. I seem to remember that 'car' is the equivalent of newLISP's 'first' function, and it's obviously a favourite (but not available by default in newLISP):</p>

<pre><code>2008-01-07 03:25:17 72.453.32.16 (car '(a b c))
invalid function : (car '(a b c))

2008-01-03 19:40:50 83.453.305.64 (car (cons 1 "a" 3.45  'foo))
invalid function : (car (cons 1 "a" 3.45 'foo))

2008-01-07 03:25:01 73.453.32.16 (cons '(a b c))
((a b c))

2008-01-10 20:41:37 63.453.379.30 (foldr list 'end '(a b c d))
invalid function : (foldr list 'end '(a b c d))
</code></pre>

<p>I've not heard of 'foldr'. </p>

<p>But here's a fun entry that set me thinking:</p>

<pre><code>2008-01-10 20:47:45 65.453.379.30 (apply (lambda (x) (* x 2)) '(1 2 3))
2
</code></pre>

<p>Why does this return 2 - and not 6, for example, which I might have expected, although I would have used 'map':</p>

<pre><code>(map (lambda (x) (* x 2)) '(1 2 3))
(2 4 6)
</code></pre>

<p>The other big drawback with the whole idea of the Lambdalator is that it's not possible to have a persistent newLISP interpreter online in this way. Well, it's probably possible, but I know that my current host doesn't allow persistent processes, and I expect there are other issues to think about. At the moment the web page gives the illusion of some persistence, with the 'paper tape' feature of a typical desktop calculator keeping a record of what's been processed, but of course in reality every time an expression is submitted a new session is started with no record of any previous entries.</p>

<p>I think I'll keep the Lambdalator online for a few more weeks, since it's interesting to watch what people make of it, and I make use of it myself occasionally. I've yet to see anyone trying to hack the security, which will be interesting - and possibly worrying - to watch.</p>

        
]]></content>
  </entry>


<entry>
   <title>Lisp in web pages</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/lispinwebpages" /> 
   <id>http://unbalanced-parentheses.nfshost.com/lispinwebpages</id> 
   <published>2008-01-06T10:39:39Z</published>
   <updated>2008-01-06T10:39:39Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>The next paragraph took me about an hour to write. And I didn't write all of it.</p>

<p><em>You downloaded this page on Fri Aug 29 04:14:59 2008.</em></p>

<p>The idea is that I can include some raw newLISP that gets evaluated only when the page is generated and displayed in the browser.</p>

<p>I stole this cool idea from <a href="http://www.alh.net/newlisp/phpbb/viewtopic.php?t=1605&amp;highlight=html">Jeff's  post</a> in the newLISP forum. </p>

<p>The newLISP code goes between two tags. I'm using <code>{% and %}</code>, which looks like a reasonable choice.</p>

<p>This is the <em>render</em> function I'm using:</p>

<pre><code><span class="pr">(</span><span class="p">define</span> <span class="pr">(</span><span class="nl">render</span> <span class="l">t</span><span class="pr">)</span>
    <span class="pr">(</span><span class="p">replace</span> <span class="s">{{ %(.*?)% }}</span>
       <span class="c">; spaces inserted between { and % !!!</span>
        <span class="l">t</span> <span class="pr">(</span><span class="p">if</span> <span class="pr">(</span><span class="p">catch</span>
                <span class="pr">(</span><span class="p">eval-string</span> <span class="s">$1</span><span class="pr">)</span> <span class="q">'</span><span class="l">result</span><span class="pr">)</span>
            <span class="pr">(</span><span class="p">string</span> <span class="l">result</span><span class="pr">)</span>
            <span class="pr">(</span><span class="p">string</span> <span class="s">" [inline error: "</span> <span class="s">$1</span> <span class="s">"] "</span><span class="pr">)</span><span class="pr">)</span> <span class="i">0</span><span class="pr">)</span><span class="pr">)</span>

</code></pre>

<p>Unfortunately, because this code contains the magic tags, it wouldn't have displayed correctly had I not put spaces between the "{" and "%" characters. The engineer hoist with his own petard, or something.</p>

<p><!-- your ip address is 38.103.63.60 --></p>

        
]]></content>
  </entry>


<entry>
   <title>Vote for somebody!</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/voteforsomebody" /> 
   <id>http://unbalanced-parentheses.nfshost.com/voteforsomebody</id> 
   <published>2007-12-31T10:11:10Z</published>
   <updated>2007-12-31T10:11:10Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>2007 has been a great year for newLISPers! We've seen a new graphics toolkit, two major releases (9.1 and 9.2), a movie trilogy, two objected-oriented frameworks, a superfast editor written in newLISP, a newlispweb web framework, the newLISP fan club wiki, a brace of new bloggers, and lots of good code from some skilled programmers.</p>

<p>I also managed to write a bit of code this year, including this blogging engine (the LamdbaPress), various GUI apps, source-code formatting, a port of Markdown (I never want to look at that code again!), and a TEX to HTML translator that produces the Introduction to newLISP (which is kindly hosted at <a href="http://newlisp.org)">newlisp.org</a>. None of this code would win any prizes for elegance or idiomatic Lispiness (or even reliability); but we all do what we're best at!</p>

<p>However, there <em>are</em> prizes to be won: don't forget to vote for some of the elegant and ingenious entries in the <a href="http://www.alh.net/newlisp/phpbb/viewforum.php?f=5">newLISP 2007 competition</a>. You have a few more days to vote...</p>

<p>And if you didn't get round to submitting an entry for this year's competition, get coding for the 2008 competition!</p>

<p>As ever, a big thanks to Lutz and everyone in the newLISP community for your contributions over the year. 2007 has been fun.</p>

<p>Now for 2008!</p
        
]]></content>
  </entry>


<entry>
   <title>The Lambdalator</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/thelambdalator" /> 
   <id>http://unbalanced-parentheses.nfshost.com/thelambdalator</id> 
   <published>2007-12-29T16:34:38Z</published>
   <updated>2007-12-29T16:34:38Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>I've added a link to my current experiment - an online interactive Lisp web page - to the list of links  on the right. The eventual aim is to get Lisp (newLISP of course) on an iPhone. Have a go! </p
        
]]></content>
  </entry>


<entry>
   <title>Christmas lunacy</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/christmaslunacy" /> 
   <id>http://unbalanced-parentheses.nfshost.com/christmaslunacy</id> 
   <published>2007-12-12T15:29:44Z</published>
   <updated>2007-12-12T15:29:44Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>If you're stuck for gift ideas this christmas, how about printing out a paper version of <a href="http://unbalanced-parentheses.nfshost.com/downloads/moon-calendar-en.pdf">this 2008 lunar calendar</a>, generated and drawn by a newLISP script with some help from PostScript and PDF?</p>

<p>I spent a few minutes trying to generate this calendar in languages other than English. (That "en" is a clue!) It was easy enough to produce the month and day names in the different languages, using newLISP's set-locale function:</p>

<pre><code><span class="pr">(</span><span class="p">set-locale</span> <span class="s">"nl_NL"</span><span class="pr">)</span>

<span class="c">; netherlands</span>
<span class="pr">(</span><span class="p">set</span> <span class="q">'</span><span class="nl">day-of-week</span>
    <span class="pr">(</span><span class="p">date</span> <span class="nl">start-date</span> <span class="i">0</span> <span class="s">{%A}</span><span class="pr">)</span><span class="pr">)</span>

<span class="c">;-&gt; "woensdag"</span>
<span class="pr">(</span><span class="p">set-locale</span> <span class="s">"C"</span><span class="pr">)</span>

<span class="c">; quickly back to default locale</span>

</code></pre>

<p>But unfortunately I think PostScript isn't very clever when it comes to Unicode, and it failed to translate the strings properly. It's not much of a problem for some languages, but it's more serious for others (and disastrous for Russian):</p>

<p>среда</p>

<p>so until I work out how to get Unicode strings from newLISP to PDF via PostScript, I'm going to stick with English. If you have any clues, please let me know - the internet has let me down, again!</p>

        
]]></content>
  </entry>


<entry>
   <title>Adventures in newbie-newLISPland</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/adventuresinnewbienewlispland" /> 
   <id>http://unbalanced-parentheses.nfshost.com/adventuresinnewbienewlispland</id> 
   <published>2007-12-06T12:27:57Z</published>
   <updated>2007-12-06T12:27:57Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>I've been looking through some of my first attempts at programming in newLISP. One thing I noticed was that at first I had trouble working out how to step through a list and process adjacent elements one pair at a time. Come with me now back to newLISP-newbie land!</p>

<p>To reduce the problem to its simplest case, suppose that we want to work through a list looking at each pair of items:</p>

<pre><code>(set 't (sequence 0 13))

0 and 1
1 and 2
...
12 and 13
</code></pre>

<p>Solutions are easy to see now, but for some reason I could think only of using <em>dolist</em> or <em>for</em>, which are the more conventional tools for working through lists.</p>

<p><em>dolist</em> keeps the current position in the list in a system variable $idx, so you can use that to find the next element, given that the loop variable <em>i</em> is the current element.</p>

<pre><code><span class="pr">(</span><span class="p">dolist</span> <span class="pr">(</span><span class="nl">i</span> <span class="l">t</span><span class="pr">)</span>
    <span class="pr">(</span><span class="p">println</span> <span class="s">{ processing }</span> <span class="nl">i</span> <span class="s">{ and }</span>
        <span class="pr">(</span><span class="l">t</span> <span class="pr">(</span><span class="p">+</span> <span class="i">$idx</span> <span class="i">1</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span>

</code></pre>

<p>Here, the implicit addressing (t $idx) returns the same element as <em>i</em>, so the next one is obviously <code>(t (+ $idx 1))</code>.</p>

<p>But there's a trap for the newbie:</p>

<pre><code>processing 0 and 1
...
processing 12 and 13
processing 13 and 13
</code></pre>

<p>Helpfully, newLISP won't crash your scripts just because you overstepped the end of a list, but it definitely <em>is</em> your job to stop processing the list at the right stage.</p>

<p>So let's add a break condition:</p>

<pre><code><span class="pr">(</span><span class="p">dolist</span> <span class="pr">(</span><span class="nl">i</span> <span class="l">t</span> <span class="pr">(</span><span class="p">=</span> <span class="i">$idx</span>
            <span class="pr">(</span><span class="p">-</span> <span class="pr">(</span><span class="p">length</span> <span class="l">t</span><span class="pr">)</span> <span class="i">1</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span>
    <span class="pr">(</span><span class="p">println</span> <span class="s">{ processing }</span> <span class="nl">i</span> <span class="s">{ and }</span>
        <span class="pr">(</span><span class="l">t</span> <span class="pr">(</span><span class="p">+</span> <span class="i">$idx</span> <span class="i">1</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span>

</code></pre>

<p>This now stops the loop when the penultimate item in the list has been processed.</p>

<p>How about <em>for</em>? This can also work:</p>

<pre><code><span class="pr">(</span><span class="p">for</span> <span class="pr">(</span><span class="nl">i</span> <span class="i">0</span> <span class="pr">(</span><span class="p">-</span> <span class="pr">(</span><span class="p">length</span> <span class="l">t</span><span class="pr">)</span> <span class="i">2</span><span class="pr">)</span><span class="pr">)</span>
    <span class="pr">(</span><span class="p">println</span> <span class="s">{ processing }</span>
        <span class="pr">(</span><span class="l">t</span> <span class="nl">i</span><span class="pr">)</span> <span class="s">{ and }</span>
        <span class="pr">(</span><span class="l">t</span> <span class="pr">(</span><span class="p">+</span> <span class="nl">i</span> <span class="i">1</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span><span class="pr">)</span>

</code></pre>

<p>It's easy to make mistakes if you're not concentrating; there are 14 elements in the list; we use index numbers 0 to 13 to get them; with <em>for</em> loops that means stopping at one less than the length; and as we're doing pairs we stop two before the length.</p>

<p>But there must be a better way. How about using <em>apply</em>?</p>

<pre><code><span class="pr">(</span><span class="p">apply</span>
    <span class="pr">(</span><span class="la">fn</span> <span class="pr">(</span><span class="nl">a</span> <span class="nl">b</span><span class="pr">)</span>
        <span class="pr">(</span><span class="p">println</span> <span class="s">{ processing }</span> <span class="nl">a</span> <span class="s">{ and }</span> <span class="nl">b</span><span class="pr">)</span><span class="pr">)</span> <span class="l">t</span> <span class="i">2</span><span class="pr">)</span>

</code></pre>

<p>See that last '2'. The anonymous function uses two arguments, and the 2 tells <em>apply</em> to use two arguments at a time. It <em>looks</em> like it works nicely:</p>

<pre><code>processing 0 and 1
...
processing 12 and 13
</code></pre>

<p>But the newLISP manual says that the result of each application is re-used as the first argument for the next application. What's happening is that the result of that <em>println</em> expression was the last number evaluated (which was b), and that was also, conveniently enough, the value that we wanted to use as the first number for the next pair.</p>

<p>To see what's going on, make the lambda function return something else:</p>

<pre><code><span class="pr">(</span><span class="p">apply</span>
    <span class="pr">(</span><span class="la">fn</span> <span class="pr">(</span><span class="nl">a</span> <span class="nl">b</span><span class="pr">)</span>
        <span class="pr">(</span><span class="p">string</span> <span class="nl">a</span> <span class="s">{ and }</span> <span class="nl">b</span><span class="pr">)</span><span class="pr">)</span> <span class="l">t</span> <span class="i">2</span><span class="pr">)</span>

<span class="c">;-&gt;</span>
 <span class="s">"0 and 1 and 2 and 3 and 4 and 5 and 6 and 7 and 8 and 9 and 10 and 11 and 12 and 13"</span>
</code></pre>

<p>So I think it's possible to use <em>apply</em> to apply a function to pairs of items if you remember to return the value of the last member of each pair, so that <em>apply</em> can use it for the next pair. </p>

<p>And you could use <em>map</em>:</p>

<pre><code><span class="pr">(</span><span class="p">map</span>
    <span class="pr">(</span><span class="la">fn</span> <span class="pr">(</span><span class="nl">a</span> <span class="nl">b</span><span class="pr">)</span>
        <span class="pr">(</span><span class="p">println</span> <span class="nl">a</span> <span class="s">{ }</span> <span class="nl">b</span><span class="pr">)</span><span class="pr">)</span>
    <span class="pr">(</span><span class="p">chop</span> <span class="l">t</span><span class="pr">)</span>
    <span class="pr">(</span><span class="p">rotate</span> <span class="l">t</span> <span class="i">-1</span><span class="pr">)</span><span class="pr">)</span>

</code></pre>

<p>which uses two versions of the list, chopping the end of one and rotating the second. Helpfully, the extra element in the second list is ignored.</p>

<p>More solutions welcome!</p>

<div><h3>Comment from <a href="http://newlisp.org" rel="nofollow">Lutz</a></h3><p>... and here is yet another one:</p>

<pre>
(set 'theList (sequence 0 13))

(dolist (t (explode theList 2 true))
    (println "processing " (t 0) "and " (t 1)))
</pre>

<p>the 'true' flag in the explode expression makes sure that only full pairs are processed if 'theList' has an uneven number of elements.</p>

<p>ps: thanks for putting on the Santa theme again ;-)</p></div<div><h3>Comment from <a href="http://unbalanced-parentheses.nfshost.com/" rel="nofollow">newlisper</a></h3><p>So suitable for even-length lists...</p>

<p>(I don't know why Santa deserted the site for a day... :-)</p></div<div><h3>Comment from <a href="http://adam.schmideg.net" rel="nofollow">talk.do.stop</a></h3><p>My version (both for odd and even lists):</p>

<p>;newlisp</p>

<pre><code>(map 
  (fn (x y) (println x " and " y)) 
  (0 -1 theList) 
  (rest theList))
</code></pre></di
        
]]></content>
  </entry>


<entry>
   <title>Newsfeeding</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/newsfeeding" /> 
   <id>http://unbalanced-parentheses.nfshost.com/newsfeeding</id> 
   <published>2007-12-06T09:20:25Z</published>
   <updated>2007-12-06T09:20:25Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>I've been playing with the Atom newsfeed script again. I'm sorry if you've noticed it playing up recently.</p>

<p>My newsreader (NetNewsWIre) tries to merge old posts with the contents of the incoming news feed, and I ended up with quite a few duplicated entries. The best way to clear this up is probably to unsubscribe and resubscribe again!</p>

<p>The latest iteration of atom.cgi (available on the downloads page) collects the five most recent posts and the ten most recent comments (I don't know whether there's an interface to set this externally?). It displays them mixed and sorted chronologically, and sets the 'update' date to the date of the most recent item. </p>

<p>With any luck, this will all work nicely. For a while!</p>

        
]]></content>
  </entry>


<entry>
   <title>Formatting</title>
   <link rel="alternate" type="text/html" href="http://unbalanced-parentheses.nfshost.com/formatting" /> 
   <id>http://unbalanced-parentheses.nfshost.com/formatting</id> 
   <published>2007-12-02T23:55:49Z</published>
   <updated>2007-12-02T23:55:49Z</updated>
   <author>
     <name>newlisper</name>
     <uri>http://unbalanced-parentheses.nfshost.com/</uri>
   </author>

<content type="html" xml:base="http://unbalanced-parentheses.nfshost.com/" xml:lang="en"><![CDATA[
        
        
<p>I decided to have another go at the syntax colouring and code formatting stuff this week. And this time I decided to try and do the job more thoroughly.</p>

<p>The first part of the task is to convert the newLISP source code into a list of elements. So, given some code like this:</p>

<pre><code><span class="pr">(</span><span class="p">cond</span>
    <span class="pr">(</span><span class="pr">(</span><span class="p">=</span> <span class="nl">start</span> <span class="nl">end</span><span class="pr">)</span>
        <span class="pr">(</span><span class="p">push</span> <span class="pr">(</span><span class="p">list</span> <span class="s">"white-space"</span> <span class="nl">source-string</span><span class="pr">)</span> <span class="nl">token-list</span> <span class="i">-1</span><span class="pr">)</span><span class="pr">)</span>
</code></pre>

<p>the resulting list of lists looks like this:</p>

<pre><code><span class="pr">(</span><span class="s">"left-paren"</span> <span class="s">"("</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"cond"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"left-paren"</span> <span class="s">"("</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"left-paren"</span> <span class="s">"("</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"="</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"start"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"end"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"right-paren"</span> <span class="s">")"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"left-paren"</span> <span class="s">"("</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"push"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"left-paren"</span> <span class="s">"("</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"list"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"quoted-string"</span> <span class="s">"\"white-space\""</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"source-string"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"right-paren"</span> <span class="s">")"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"token-list"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"code"</span> <span class="s">"-1"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"right-paren"</span> <span class="s">")"</span><span class="pr">)</span>

<span class="pr">(</span><span class="s">"right-paren"</span> <span class="s">")"</span><span class="pr">)</span>

</code></pre>

<p>This format is a bit wordy, but it's readable, and useful for when thi