<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Nerdiest Place on Earth &#187; LISP</title>
	<atom:link href="http://jasonswett.net/category/software-development/lisp/feed/" rel="self" type="application/rss+xml" />
	<link>http://jasonswett.net</link>
	<description>A Blog About Software Development, Databases, And Stuff That Doesn&#039;t Have To Do With Computers</description>
	<lastBuildDate>Wed, 08 Sep 2010 01:33:23 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The Common Lisp Word Scrambler, Part 2</title>
		<link>http://jasonswett.net/the-common-lisp-word-scrambler-part-2/</link>
		<comments>http://jasonswett.net/the-common-lisp-word-scrambler-part-2/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 21:51:11 +0000</pubDate>
		<dc:creator>jason</dc:creator>
				<category><![CDATA[LISP]]></category>

		<guid isPermaLink="false">http://jasonswett.net/blog/?p=227</guid>
		<description><![CDATA[I&#8217;ve added some stuff to my word scrambler.
I added a function that prompts you for each permutation of a word and asks you if it&#8217;s valid or not:

CL-USER> (check-word "cat")
Is "cat" a valid word? (I think it's not.) (y/n) y

Is "cta" a valid word? (I think it's not.) (y/n) n

Is "act" a valid word? (I [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve added some stuff to my word scrambler.</p>
<p>I added a function that prompts you for each permutation of a word and asks you if it&#8217;s valid or not:</p>
<pre>
CL-USER> (check-word "cat")
Is "cat" a valid word? (I think it's not.) (y/n) y

Is "cta" a valid word? (I think it's not.) (y/n) n

Is "act" a valid word? (I think it's not.) (y/n) y

Is "atc" a valid word? (I think it's not.) (y/n) n

Is "tca" a valid word? (I think it's not.) (y/n) n

Is "tac" a valid word? (I think it's not.) (y/n) y

T
CL-USER>
</pre>
<p>In the process, it keeps track of valid and invalid words:</p>
<pre>
CL-USER> *valid-words*
("tac" "act" "cat")
CL-USER> *invalid-words*
("tca" "atc" "cta")
CL-USER>
</pre>
<p>Then, if I run it again, it &#8220;learns&#8221; (in a very, very rudimentary way) which words are valid and which aren&#8217;t:</p>
<pre>
CL-USER> (check-word "cat")
Is "cat" a valid word? (I think it is.) (y/n) y

Is "cta" a valid word? (I think it's not.) (y/n) n

Is "act" a valid word? (I think it is.) (y/n) y

Is "atc" a valid word? (I think it's not.) (y/n) n

Is "tca" a valid word? (I think it's not.) (y/n) n

Is "tac" a valid word? (I think it is.) (y/n) y

T
CL-USER>
</pre>
<p>The obvious missing piece is that the program can&#8217;t infer rules based on the facts you give it. I don&#8217;t really know how I might make it do that. Here&#8217;s the code for what I have so far:</p>
<pre>
(defparameter *valid-words* nil)
(defparameter *invalid-words* nil)
(defparameter *valid-words-filename* "valid-words.txt")
(defparameter *invalid-words-filename* "invalid-words.txt")

(defun all-permutations (list)
  (cond ((null list) nil)
        ((null (cdr list)) (list list))
        (t (loop for element in list
             append (mapcar (lambda (l) (cons element l))
                            (all-permutations (remove element list)))))))

(defun make-distinct (list)
  (let ((count 0)
        (result nil))
    (dolist (element list)
      (push (list element count) result)
      (incf count))
  (reverse result)))

(defun make-simple (list)
  (let ((result nil))
    (dolist (element list)
      (push (first element) result))
    (reverse result)))

(defun clean-list (list)
  (let ((result nil))
    (dolist (element list)
      (push (list-to-string (make-simple element)) result))
    (reverse result)))

(defun scramble-list (list)
  (clean-list (all-permutations (make-distinct list))))

(defun scramble (string)
  (remove-duplicates
   (scramble-list (loop for char across string collect char))
   :test #'string-equal))

(defun list-to-string (list)
  (concatenate 'string list))

(defun user-thinks-word-is-valid (word)
  (let ((opinion))
    (if (is-valid word)
        (setf opinion "I think it is.")
        (setf opinion "I think it's not."))
  (y-or-n-p (format nil "Is \"~a\" a valid word? (~a)" word opinion))))

(defun check-word (word)
  (dolist (scrambley (scramble word))
    (if (user-thinks-word-is-valid scrambley)
        (push scrambley *valid-words*)
        (push scrambley *invalid-words*)))
  (save-words))

(defun save-words ()
  (save *valid-words-filename* *valid-words*)
  (save *invalid-words-filename* *invalid-words*)
  t)

(defun save (filename expression)
  (with-open-file (out filename :direction :output :if-exists :supersede)
    (with-standard-io-syntax
      (print expression out))))

(defun load-from-file (filename)
  (with-open-file (in filename)
    (with-standard-io-syntax
      (read in))))

(defun load-words ()
  (setf *valid-words* (load-from-file *valid-words-filename*))
  (setf *invalid-words* (load-from-file *invalid-words-filename*)))

(defun is-valid (word)
  (if (find word *valid-words* :test #'string-equal) t))
</pre>
]]></content:encoded>
			<wfw:commentRss>http://jasonswett.net/the-common-lisp-word-scrambler-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Common Lisp Word Scrambler</title>
		<link>http://jasonswett.net/the-common-lisp-word-scrambler/</link>
		<comments>http://jasonswett.net/the-common-lisp-word-scrambler/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 19:26:07 +0000</pubDate>
		<dc:creator>jason</dc:creator>
				<category><![CDATA[LISP]]></category>

		<guid isPermaLink="false">http://jasonswett.net/blog/?p=221</guid>
		<description><![CDATA[In a previous post, I said that I&#8217;d like to write a program that gives me all the permutations of the letters in a word that spell valid English words. Well, I&#8217;ve gotten a significant portion of the way there. I have a function that will take any word and scramble it into all its [...]]]></description>
			<content:encoded><![CDATA[<p>In a <a href="/my-first-lisp-program/">previous post</a>, I said that I&#8217;d like to write a program that gives me all the permutations of the letters in a word that spell valid English words. Well, I&#8217;ve gotten a significant portion of the way there. I have a function that will take any word and scramble it into all its possible permutations, valid English or not. Here are a few examples:</p>
<pre>CL-USER&gt; (scramble "hi")
("hi" "ih")
CL-USER&gt; (scramble "the")
("the" "teh" "hte" "het" "eth" "eht")
CL-USER&gt; (scramble "horse")
("horse" "hores" "hosre" "hoser" "hoers" "hoesr" "hrose" "hroes" "hrsoe"
 "hrseo" "hreos" "hreso" "hsore" "hsoer" "hsroe" "hsreo" "hseor" "hsero"
 "heors" "heosr" "heros" "herso" "hesor" "hesro" "ohrse" "ohres" "ohsre"
 "ohser" "ohers" "ohesr" "orhse" "orhes" "orshe" "orseh" "orehs" "oresh"
 "oshre" "osher" "osrhe" "osreh" "osehr" "oserh" "oehrs" "oehsr" "oerhs"
 "oersh" "oeshr" "oesrh" "rhose" "rhoes" "rhsoe" "rhseo" "rheos" "rheso"
 "rohse" "rohes" "roshe" "roseh" "roehs" "roesh" "rshoe" "rsheo" "rsohe"
 "rsoeh" "rseho" "rseoh" "rehos" "rehso" "reohs" "reosh" "resho" "resoh"
 "shore" "shoer" "shroe" "shreo" "sheor" "shero" "sohre" "soher" "sorhe"
 "soreh" "soehr" "soerh" "srhoe" "srheo" "srohe" "sroeh" "sreho" "sreoh"
 "sehor" "sehro" "seohr" "seorh" "serho" "seroh" "ehors" "ehosr" "ehros"
 "ehrso" "ehsor" "ehsro" "eohrs" "eohsr" "eorhs" "eorsh" "eoshr" "eosrh"
 "erhos" "erhso" "erohs" "erosh" "ersho" "ersoh" "eshor" "eshro" "esohr"
 "esorh" "esrho" "esroh")</pre>
<p>Here&#8217;s the code:</p>
<pre>(defun all-permutations (list)
  (cond ((null list) nil)
        ((null (cdr list)) (list list))
        (t (loop for element in list
             append (mapcar (lambda (l) (cons element l))
                            (all-permutations (remove element list)))))))

(defun make-distinct (list)
  (let ((count 0)
        (result nil))
    (dolist (element list)
      (push (list element count) result)
      (incf count))
  (reverse result)))

(defun make-simple (list)
  (let ((result nil))
    (dolist (element list)
      (push (first element) result))
    (reverse result)))

(defun clean-list (list)
  (let ((result nil))
    (dolist (element list)
      (push (list-to-string (make-simple element)) result))
    (reverse result)))

(defun scramble-list (list)
  (clean-list (all-permutations (make-distinct list))))

(defun scramble (string)
  (scramble-list (loop for char across string collect char)))

(defun list-to-string (list)
  (concatenate 'string list))</pre>
<p>The next step will be to make the program generate only valid English words. My initial thought here was that I would program in all the rules for what makes a valid English word. After I thought about that a little bit, though, I realized that I can&#8217;t even think of all the rules or even necessarily express what they are. I just know a valid English word when I see it.</p>
<p>For this reason, I thought it might be better to make the computer learn, with human help, what sequences are valid or invalid. This might be done by generating a list, then asking a person which items are valid. Let&#8217;s take the output of &#8220;apple&#8221; as an example:</p>
<pre>CL-USER&gt; (scramble "apple")
("apple" "appel" "aplpe" "aplep" "apepl" "apelp" "apple" "appel" "aplpe"
 "aplep" "apepl" "apelp" "alppe" "alpep" "alppe" "alpep" "alepp" "alepp"
 "aeppl" "aeplp" "aeppl" "aeplp" "aelpp" "aelpp" "paple" "papel" "palpe"
 "palep" "paepl" "paelp" "ppale" "ppael" "pplae" "pplea" "ppeal" "ppela"
 "plape" "plaep" "plpae" "plpea" "pleap" "plepa" "peapl" "pealp" "pepal"
 "pepla" "pelap" "pelpa" "paple" "papel" "palpe" "palep" "paepl" "paelp"
 "ppale" "ppael" "pplae" "pplea" "ppeal" "ppela" "plape" "plaep" "plpae"
 "plpea" "pleap" "plepa" "peapl" "pealp" "pepal" "pepla" "pelap" "pelpa"
 "lappe" "lapep" "lappe" "lapep" "laepp" "laepp" "lpape" "lpaep" "lppae"
 "lppea" "lpeap" "lpepa" "lpape" "lpaep" "lppae" "lppea" "lpeap" "lpepa"
 "leapp" "leapp" "lepap" "leppa" "lepap" "leppa" "eappl" "eaplp" "eappl"
 "eaplp" "ealpp" "ealpp" "epapl" "epalp" "eppal" "eppla" "eplap" "eplpa"
 "epapl" "epalp" "eppal" "eppla" "eplap" "eplpa" "elapp" "elapp" "elpap"
 "elppa" "elpap" "elppa")</pre>
<p>Since it&#8217;s sometimes debatable whether a word could work or not, it would probably be best to ask whether a word is definitely invalid or not, rather than the other way around.</p>
<p>Is &#8220;apple&#8221; invalid? No. Is &#8220;appel&#8221; invalid? No. Is &#8220;aplpe&#8221; invalid? Definitely. But what part of it is invalid? Knowing that it&#8217;s invalid isn&#8217;t necessarily all that useful to the computer unless we know <em>why </em>it&#8217;s invalid.</p>
<p>Maybe the way to go is to keep track of specific instances of invalid words, then see what all those words have in common and form rules based on that. For &#8220;aplpe,&#8221; the invalid parts are &#8220;aplpe,&#8221; &#8220;aplp,&#8221; &#8220;plpe,&#8221; &#8220;apl,&#8221; &#8220;plp,&#8221; &#8220;lpe,&#8221; &#8220;pl,&#8221; &#8220;lp,&#8221;, &#8220;p&#8221; and &#8220;l&#8221;. The valid parts are &#8220;ap,&#8221; &#8220;pe&#8221; and &#8220;a&#8221;.</p>
<p>So far, here&#8217;s our list of valid words and invalid words:</p>
<table>
<tbody>
<tr>
<th>Valid</th>
<th>Invalid</th>
</tr>
<tr>
<td>
<ul>
<li>apple</li>
<li>appel</li>
<li>ap</li>
<li>pe</li>
<li>a</li>
</ul>
</td>
<td>
<ul>
<li>aplpe</li>
<li>aplp</li>
<li>plpe</li>
<li>apl</li>
<li>lpe</li>
<li>pl</li>
<li>lp</li>
<li>p</li>
<li>l</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>Let&#8217;s move on to a slightly more interesting example. One of the permutations of is &#8220;peapl,&#8221; which is invalid. Add an &#8220;e&#8221; to the end of that to make &#8220;peaple,&#8221; though and it&#8217;s fine. Let&#8217;s see what happens when we apply the foregoing technique to this invalid word:</p>
<p>Invalid parts: eapl, apl, pl, p, l</p>
<p>Valid parts: peap, pea, eap, pe, ea, ap, a</p>
<p>That makes this our new list:</p>
<table>
<tbody>
<tr>
<th>Valid</th>
<th>Invalid</th>
</tr>
<tr>
<td>
<ul>
<li>apple</li>
<li>appel</li>
<li>peap</li>
<li>eap</li>
<li>pea</li>
<li>ap</li>
<li>pe</li>
<li>a</li>
</ul>
</td>
<td>
<ul>
<li>aplpe</li>
<li>aplp</li>
<li>eapl</li>
<li>plpe</li>
<li>apl</li>
<li>lpe</li>
<li>pl</li>
<li>lp</li>
<li>p</li>
<li>l</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>I just noticed that I missed something. If we&#8217;re dissecting the invalid words and adding the valid and invalid parts to our list, we should be doing the same thing, or at least something similar, with the valid words. But since all parts of a valid word are valid letter sequences, shouldn&#8217;t every part of a valid word end up in the &#8220;valid&#8221; column? What happens if we do this for the word &#8220;apple&#8221;?</p>
<p>Valid parts: app, ple, ap, le</p>
<p>Invalid parts: appl, pple, ppl, pp, pl</p>
<p>That&#8217;s a little disconcerting. What we&#8217;ve illustrated here is that valid words can be comprised of invalid letter sequences, as long as some other letters before or after the invalid sequence set things straight again. What&#8217;s the difference between the &#8220;pl&#8221; in &#8220;ap<strong>pl</strong>e&#8221; and the &#8220;pl&#8221; in &#8220;pea<strong>pl</strong>&#8220;? What&#8217;s the difference between the &#8220;pp&#8221; in &#8220;a<strong>pp</strong>le&#8221; and the &#8220;pp&#8221; in &#8220;<strong>pp</strong>l&#8221;? Well, in those particular cases, &#8220;pl&#8221; can&#8217;t end a word and &#8220;pp&#8221; can&#8217;t be followed by a consonant. The only way to really preserve these distinctions is to keep track of the entire word in the valid/invalid list.</p>
<p>Even though our latest findings make things a little more complicated, they don&#8217;t make our valid/invalid list any less true. All the words in the &#8220;valid&#8221; list are valid and all the ones in the &#8220;invalid&#8221; list are not. However, just because a word contains something invalid doesn&#8217;t mean the entire word is invalid. The only good our list does for us right now is it tells us that if a word exactly matches something on the &#8220;invalid&#8221; list, it&#8217;s not valid. That&#8217;s not a terribly comprehensive solution. We&#8217;ll have to come up with something better.</p>
<p>More thoughts to come on this in future posts. My brain hurts.</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonswett.net/the-common-lisp-word-scrambler/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Converting a List to a String in Common Lisp</title>
		<link>http://jasonswett.net/converting-a-list-to-a-string-in-common-lisp/</link>
		<comments>http://jasonswett.net/converting-a-list-to-a-string-in-common-lisp/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 17:59:16 +0000</pubDate>
		<dc:creator>jason</dc:creator>
				<category><![CDATA[LISP]]></category>

		<guid isPermaLink="false">http://jasonswett.net/blog/?p=217</guid>
		<description><![CDATA[A Google search for &#8220;lisp list to string&#8221; doesn&#8217;t give you anything too helpful, which is kind of weird because it&#8217;s really easy.
The CONCATENATE function lets you concatenate any number of items into whatever type of thing you want. Since CONCATENATE is fine with any number of arguments as long as you give it a [...]]]></description>
			<content:encoded><![CDATA[<p>A Google search for &#8220;lisp list to string&#8221; doesn&#8217;t give you anything too helpful, which is kind of weird because it&#8217;s really easy.</p>
<p>The <code>CONCATENATE </code>function lets you concatenate any number of items into whatever type of thing you want. Since <code>CONCATENATE </code>is fine with any number of arguments as long as you give it a type, you can pass it just one list, like this:</p>
<pre>CL-USER&gt; (concatenate 'string '(#\h #\e #\l #\l #\o))
"hello"
</pre>
<p>That&#8217;s all.</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonswett.net/converting-a-list-to-a-string-in-common-lisp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Recursion in Lisp</title>
		<link>http://jasonswett.net/recursion-in-lisp/</link>
		<comments>http://jasonswett.net/recursion-in-lisp/#comments</comments>
		<pubDate>Thu, 14 Jan 2010 22:23:33 +0000</pubDate>
		<dc:creator>jason</dc:creator>
				<category><![CDATA[LISP]]></category>

		<guid isPermaLink="false">http://jasonswett.net/blog/?p=208</guid>
		<description><![CDATA[Although I&#8217;m no stranger to recursion, it took me a little bit to figure out how to do it in Lisp. Today I decided to see if I could write up a simple example.
I set my sights low for the goal: I want to take a list and print the whole thing, then all but [...]]]></description>
			<content:encoded><![CDATA[<p>Although I&#8217;m no stranger to recursion, it took me a little bit to figure out how to do it in Lisp. Today I decided to see if I could write up a simple example.</p>
<p>I set my sights low for the goal: I want to take a list and print the whole thing, then all but the first item, then all but the first two items, and so on until there&#8217;s only one item left. For example, if I had the list <code>(1 2 3 4)</code>, the output would look like this:</p>
<pre>
(1 2 3 4)
(2 3 4)
(3 4)
(4)
</pre>
<p>With all recursive functions, you need a base case, and the base case here would be that the length of the list is one. The <code>LENGTH </code>function is good for that:</p>
<pre>
CL-USER> (length (list 1 2 3 4))
4
CL-USER> (length (list 1))
1
</pre>
<p>That tells us the length of a list, but we aren&#8217;t really interested in the length of our list. We don&#8217;t need to be that specific. We just want to know whether the list is longer than 1 or not. We can get that with a simple call to the > function:</p>
<pre>
CL-USER> (> (length (list 1 2 3 4)) 1)
T
CL-USER> (> (length (list 1)) 1)
NIL
</pre>
<p>To make than easier to grab a hold of, let&#8217;s define a function:</p>
<pre>
CL-USER> (defun longer-than-1 (list)
           (if (> (length list) 1) t))
LONGER-THAN-1
CL-USER> (longer-than-1 (list 1 2 3 4))
T
CL-USER> (longer-than-1 (list 1))
NIL
</pre>
<p>Now that we have that taken care of, let&#8217;s turn our attention to the task of printing the list. To print text, you can use <code>FORMAT </code>like this:</p>
<pre>
CL-USER> (format t "hello, world")
hello, world
NIL
</pre>
<p>The same doesn&#8217;t quite work for lists, though. If you try to do <code>(format t (list 1 2 3 4))</code>, you&#8217;ll get an error. You need the flag <code>~s</code>, which stands for s-expression, in order to do that:</p>
<pre>
CL-USER> (format t "~s" (list 1 2 3 4))
(1 2 3 4)
NIL
</pre>
<p>Now that we have printing and length-figuring-out under control, writing the function that prints a shrinking version of the list isn&#8217;t too hard:</p>
<pre>
(defun show-list (list)
  (format t "~s" list)
  (if (eql (longer-than-1 list) t)
      (show-list (rest list))
      nil))
</pre>
<p>The first line should look familiar; that&#8217;s where we print the list. The rest of the function is just one more function call to <code>IF</code>. If the list is longer than 1, show the rest of the list. Otherwise don&#8217;t do anything. Let&#8217;s see how it runs:</p>
<pre>
CL-USER> (show-list (list 1 2 3 4))
(1 2 3 4)(2 3 4)(3 4)(4)
NIL
</pre>
<p>Pretty good, except it might be nice if there were a newline between each list. We can do that with a <code>~n</code>, like this:</p>
<pre>
(format t "~s~%" list)
</pre>
<p>Now let&#8217;s see how it behaves:</p>
<pre>
CL-USER> (show-list (list 1 2 3 4))
(1 2 3 4)
(2 3 4)
(3 4)
(4)
NIL
</pre>
<p>That looks just like our original goal, so it looks like we got it right. Here&#8217;s the full program:</p>
<pre>
(defun longer-than-1 (list)
  (if (> (length list) 1) t))

(defun show-list (list)
  (format t "~s~%" list)
  (if (eql (longer-than-1 list) t)
      (show-list (rest list))
      nil))
</pre>
<p>Although I&#8217;m usually of the opinion &#8220;the shorter, the better&#8221; for functions, I&#8217;m not sure that we&#8217;re making things any simpler by moving the length test into the <code>LONGER-THAN-1 </code>function. I&#8217;m going to bring that logic into the <code>SHOW-LIST </code>function.</p>
<pre>
(defun show-list (list)
  (format t "~s~%" list)
  (if (> (length list) 1)
      (show-list (rest list))
      nil))
</pre>
<p>There. That&#8217;s definitely shorter and I think it&#8217;s actually a little clearer.</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonswett.net/recursion-in-lisp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>My First Lisp Program, Revised</title>
		<link>http://jasonswett.net/my-first-lisp-program-revised/</link>
		<comments>http://jasonswett.net/my-first-lisp-program-revised/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 14:34:54 +0000</pubDate>
		<dc:creator>jason</dc:creator>
				<category><![CDATA[LISP]]></category>

		<guid isPermaLink="false">http://jasonswett.net/blog/?p=191</guid>
		<description><![CDATA[In my last post, titled My First Lisp Program, I wrote a simple program that would tell me whether each letter in a word was a consonant or a vowel. The program looked like this:

(defun string-to-list (string)
  (loop for char across string collect char))

(defun is-vowel (char)
  (if (find char "aeiou") t))

(defun letter-type (char)
 [...]]]></description>
			<content:encoded><![CDATA[<p>In my last post, titled <a href="/my-first-lisp-program/">My First Lisp Program</a>, I wrote a simple program that would tell me whether each letter in a word was a consonant or a vowel. The program looked like this:</p>
<pre>
(defun string-to-list (string)
  (loop for char across string collect char))

(defun is-vowel (char)
  (if (find char "aeiou") t))

(defun letter-type (char)
  (if (is-vowel char) "vowel" "consonant"))

(defun analyze-word (word-string)
  (loop for char across word-string collect (letter-type char)))
</pre>
<p>Then someone posted a comment saying he might instead write a couple of the functions like this:</p>
<pre>
(defun letter-type (char)
  (case char ((#\a #\e #\i #\o #\u) :vowel) (t :consonant))

(defun analyze-word (word)
  (map `list `letter-type (string-downcase word)))
</pre>
<p>This code gives output that&#8217;s slightly different and, if I understand what the poster was saying, slightly faster:</p>
<pre>
CL-USER> (analyze-word "hello")
(:CONSONANT :VOWEL :CONSONANT :CONSONANT :VOWEL)
</pre>
<p>I&#8217;m certainly not concerned with speed here but it&#8217;s interesting to see how someone else would have written the same thing differently. I can&#8217;t say I fully understand how the <code>CASE </code>function works, I&#8217;ve only done seen a couple <code>MAP </code>examples and I my understanding of keys (<code>:vowel </code>and <code>:consonant </code>are keys, as opposed to &#8220;vowel&#8221; and &#8220;consonant&#8221; which are strings) is foggy at best. And what are those backticks for?</p>
<p>Conveniently, since Lisp is comprised of s-expressions (covered in <a href="http://www.gigamonkeys.com/book/syntax-and-semantics.html">this chapter</a> of <a href="http://www.amazon.com/gp/product/1590592395?ie=UTF8&#038;tag=jasonswettnet-20&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=1590592395">this book</a>), we can break these functions down and look at their building blocks separately.</p>
<h3>LETTER-TYPE and CASE</h3>
<p>Let&#8217;s look at <code>LETTER-TYPE </code>first:</p>
<pre>
(defun letter-type (char)
  (case char ((#\a #\e #\i #\o #\u) :vowel) (t :consonant))
</pre>
<p>This function relies heavily on a function called CASE. Upon closer inspection, it turns out CASE is actually a macro. The <a href="http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node84.html">CMU page for it</a> says so. They show that the form of the macro is this:</p>
<pre>
(case keyform
  (keylist-1 consequent-1-1 consequent-1-2 ...)
  (keylist-2 consequent-2-1 ...)
  (keylist-3 consequent-3-1 ...)
  ...)
</pre>
<p>Do you understand that? I don&#8217;t. They don&#8217;t give any examples, either, so that doc isn&#8217;t all that helpful, at least not to me. Let&#8217;s see if we can kind of figure out what&#8217;s going on:</p>
<pre>
(defun letter-type (char)
  (case char ((#\a #\e #\i #\o #\u) :vowel) (t :consonant))
</pre>
<p>That&#8217;s our definition for <code>LETTER-TYPE</code>. Can we pull out the <code>CASE </code>call, replace <code>char </code>with some character, and feed that through the <a href="http://www.gigamonkeys.com/book/lather-rinse-repeat-a-tour-of-the-repl.html">REPL</a>?</p>
<pre>
CL-USER> (case #\a ((#\a #\e #\i #\o #\u) :vowel) (t :consonant))
:VOWEL
</pre>
<p>Yes, we can. That&#8217;s what you would expect, too. Just to be sure, let&#8217;s try a consonant:</p>
<pre>
CL-USER> (case #\b ((#\a #\e #\i #\o #\u) :vowel) (t :consonant))
:CONSONANT
</pre>
<p>Yup. If we examine the CASE call, we can see that there are three arguments: <code>#\a</code>, <code>((#\a #\e #\i #\o #\u) :vowel)</code> and <code>(t :constant)</code>.</p>
<p>What is <code>#\a</code>? In my loose understanding, it&#8217;s a character, and that&#8217;s probably all that&#8217;s important for now.</p>
<p>What is <code>((#\a #\e #\i #\o #\u) :vowel)</code>? It&#8217;s a list. The first item is <code>(#\a #\e #\i #\o #\u)</code> and the second item is <code>:vowel</code>. Let&#8217;s not analyze it further than that just yet.</p>
<p>What is <code>(t :constant)</code>? That&#8217;s a list as well. The first element is <code>t</code> (AKA the constant <code>TRUE</code>) and the second is <code>:consonant</code>.</p>
<p>We already have one CASE example, but let&#8217;s see if we can make our own example that might be easier to understand. What about looking for a number in a list of numbers instead of looking for a character in a list of characters?</p>
<pre>
CL-USER> (case 1 ((list 1 2 3) :yes) (t :no))
:YES
</pre>
<p>That seems to have the expected output. We&#8217;re asking, is 1 in the list 1, 2, 3? It is, so the answer is yes. Let&#8217;s try looking for something that&#8217;s not there:</p>
<pre>
CL-USER> (case 5 ((list 1 2 3) :yes) (t :no))
:NO
</pre>
<p>That&#8217;s the expected output as well.</p>
<p>Now that we&#8217;re looking at CASE from a couple different angles, it&#8217;s a little easier to tell what&#8217;s going on. It seems that if the first argument (in the latter case, 5) is found in the first list (1 2 3), the output will be the item inside that form (:yes). Otherwise, it will go on to the next list. I&#8217;m guessing that the (t :no) is kind of a catch-all, and if control gets there, :no will always be the output.</p>
<pre>
CL-USER> (case 1 (t :no))
:NO
</pre>
<p>That behavior is in-line with that expectation.</p>
<p>Now that we understand the CASE macro better, maybe its form will make more sense.</p>
<pre>
(case keyform
  (keylist-1 consequent-1-1 consequent-1-2 ...)
  (keylist-2 consequent-2-1 ...)
  (keylist-3 consequent-3-1 ...)
  ...)
</pre>
<p>It certainly does. In our last numeric example, 5 is the keyform, <code>(list 1 2 3)</code> is <code>keylist-1</code>, <code>:yes</code> is <code>consequent-1-1</code>, <code>t</code> is <code>keylist-2</code> and <code>:no</code> is <code>consequent-2-1</code>.</p>
<p>There&#8217;s something a little funny, though. In the <code>LETTER-TYPE</code> function, the first keylist looked listy, but it wasn&#8217;t wrapped in a <code>LIST </code>call. Does <code>CASE </code>accept different types for its keylists or is <code>LIST </code>just not necessary?</p>
<pre>
CL-USER> (case 1 ((1 2 3) :yes) (t :no))
:YES
</pre>
<p>It looks like <code>LIST </code>is just not necessary. Our number example works just fine without it.</p>
<p>That demystifies the mysteries of <code>CASE </code>(at least enough for me, for now), and since <code>LETTER-TYPE </code>is mostly just a <code>CASE </code>call, let&#8217;s move on to <code>ANALYZE-WORD</code>.</p>
<p>Here&#8217;s what the function looks like again:</p>
<pre>
(defun analyze-word (word)
  (map `list `letter-type (string-downcase word)))
</pre>
<p>I don&#8217;t understand a lot about this function, so let&#8217;s start out with the highest-level part of it: <code>MAP</code>.</p>
<h3>The MAP Function</h3>
<p>Peter Seibel talks about MAP in the <a href="http://www.gigamonkeys.com/book/collections.html">Collections</a> chapter of his book. The first example he gives is this:</p>
<pre>
CL-USER> (map 'vector #'* #(1 2 3 4 5) #(10 9 8 7 6))
#(10 18 24 28 30)
</pre>
<p>It&#8217;s not too hard to tell what&#8217;s going on here: each number in the first list got multiplied by its corresponding number in the second list. That weird-looking argument, <code>#'*</code>, is the way you pass functions as arguments in Lisp. If we wanted to use a different function from <code>*</code>, we could:</p>
<pre>
CL-USER> (map 'vector #'list #(1 2 3 4 5) #(10 9 8 7 6))
#((1 10) (2 9) (3 8) (4 7) (5 6))
</pre>
<p>The <code>'vector </code>argument tells <code>MAP </code>that the output should be a vector. We could get a list, instead, if we wanted to:</p>
<pre>
CL-USER> (map 'list #'* #(1 2 3 4 5) #(10 9 8 7 6))
(10 18 24 28 30)
</pre>
<p>Just like we did with <code>CASE</code>, let&#8217;s pull <code>MAP </code>out and use it by itself. In place of <code>word</code>, we&#8217;ll use &#8220;hello&#8221;:</p>
<pre>
CL-USER> (map `list `letter-type (string-downcase "hello"))
(:CONSONANT :VOWEL :CONSONANT :CONSONANT :VOWEL)
</pre>
<p>That works. To make things even simpler, let&#8217;s take out the <code>STRING-DOWNCASE </code>call. All that does is makes sure everything&#8217;s lower-case.</p>
<pre>
CL-USER> (map `list `letter-type "hello")
(:CONSONANT :VOWEL :CONSONANT :CONSONANT :VOWEL)
</pre>
<p>Same thing. Since we now know what the first two parameters <code>MAP </code>expects are, <code>list </code>and <code>letter-type </code>make plenty of sense. The <code>"hello" </code>may seem odd, but we&#8217;ll get to that in a second. First, I&#8217;m curious: why does this <code>MAP </code>call use backticks when our other one used single quotes? Do they have to be backticks?</p>
<pre>
CL-USER> (map 'list 'letter-type "hello")
(:CONSONANT :VOWEL :CONSONANT :CONSONANT :VOWEL)
</pre>
<p>Apparently not. Single quotes work just as well as backticks in this case. Let&#8217;s compare our two MAP calls.</p>
<p>Example A:</p>
<pre>
(map 'vector #'* #(1 2 3 4 5) #(10 9 8 7 6))
</pre>
<p>Example B:</p>
<pre>
(map 'list 'letter-type "hello")
</pre>
<p>Example A has a vector output and Example B has a list output, but that distinction is pretty trivial. What&#8217;s more important is the function and vectors being passed. At first, I was confused as to why Example A passed two vectors and Example B only passes one, but it actually makes sense once you think about it: the <code>*</code> function accepts two parameters and <code>LETTER-TYPE</code> takes just one. And a string is just a special vector, as you can see if we do this:</p>
<pre>
CL-USER> (map 'list 'letter-type #(#\h #\e #\l #\l #\o))
(:CONSONANT :VOWEL :CONSONANT :CONSONANT :VOWEL)
</pre>
<p>So it looks like one of <code>MAP</code>&#8217;s uses is a handy way to apply a single function to each element in a list.</p>
<h3>Keys</h3>
<p>I don&#8217;t feel qualified to explain keys yet, and I can&#8217;t find any great explanation online. Perhaps a future exercise will force us to gain an understanding of keys. For this one, they&#8217;re not really necessary.</p>
<p>In any case, we learned how to use two new things: <code>CASE</code> and <code>MAP</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonswett.net/my-first-lisp-program-revised/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My First Lisp Program</title>
		<link>http://jasonswett.net/my-first-lisp-program/</link>
		<comments>http://jasonswett.net/my-first-lisp-program/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 21:52:27 +0000</pubDate>
		<dc:creator>jason</dc:creator>
				<category><![CDATA[LISP]]></category>

		<guid isPermaLink="false">http://jasonswett.net/blog/?p=160</guid>
		<description><![CDATA[Over the last couple weeks or so, I&#8217;ve been reading a book called Practical Common Lisp by Peter Seibel. (This excellent book is available on Amazon or online for free.) The book is not about Lisp that&#8217;s both practical and common as I assumed when I first read the title, but rather it&#8217;s a practical [...]]]></description>
			<content:encoded><![CDATA[<p>Over the last couple weeks or so, I&#8217;ve been reading a book called Practical Common Lisp by Peter Seibel. (This excellent book is available on <a href="http://www.amazon.com/gp/product/1590592395?ie=UTF8&amp;tag=jasonswettnet-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1590592395">Amazon</a><img style="border: none !important; margin: 0px !important;" src="http://www.assoc-amazon.com/e/ir?t=jasonswettnet-20&amp;l=as2&amp;o=1&amp;a=1590592395" border="0" alt="" width="1" height="1" /> or <a href="http://www.gigamonkeys.com/book/">online for free</a>.) The book is not about Lisp that&#8217;s both practical and common as I assumed when I first read the title, but rather it&#8217;s a practical presentation of the language known as Common Lisp. Common List is a popular dialect of the original Lisp language.</p>
<p>Armed with my new Lisp knowledge along with <a href="http://common-lisp.net/project/lispbox/">Lisp in a Box</a>, which Seibel walks you through in his <a href="http://www.gigamonkeys.com/book/lather-rinse-repeat-a-tour-of-the-repl.html">REPL</a> chapter, I decided today that I was finally ready to write my first program. Conveniently, I have a real-life problem for which Lisp is probably well-suited to solve.</p>
<p>For weird reasons I don&#8217;t feel like explaining, I want to be able to take a person&#8217;s name and shuffle the letters around however many times it takes to list all the valid English words that could be made from the letters in that person&#8217;s name. For example, the name Pat could spell &#8220;pat,&#8221; &#8220;apt&#8221; and &#8220;tap,&#8221; but not &#8220;pta,&#8221; atp&#8221; or &#8220;tpa&#8221; because the latter three aren&#8217;t valid English words.</p>
<p>At first I thought it wouldn&#8217;t be that hard to determine whether or not a word is a valid English word, but then I realized that I don&#8217;t even know how I&#8217;d explain all the rules to a human. (It looks like the key might be <a href="http://en.wikipedia.org/wiki/English_phonology#Phonotactics">phonotactics</a>, but in any case it&#8217;s too much to bite off coming straight from &#8220;hello, world.&#8221;) So I settled for the next best thing: a program that tells you whether each letter in a word is a consonant or a vowel.</p>
<p>Here&#8217;s the code I came up with:</p>
<pre>(defun string-to-list (string)
  (loop for char across string collect char))

(defun is-vowel (char)
  (if (find char "aeiou") t))

(defun letter-type (char)
  (if (is-vowel char) "vowel" "consonant"))

(defun analyze-word (word-string)
  (loop for char across word-string collect (letter-type char)))</pre>
<p>Let&#8217;s go through the reasoning for these functions one-by-one, starting with this one:</p>
<pre>(defun string-to-list (string)
  (loop for char across string collect char))</pre>
<p>The name Lisp came from LISt Processing, and list processing is something that Lisp is very good at. Since a word is nothing more than a list of letters, I thought it made sense to convert a string into a list of characters to make the string easier for Lisp to deal with. Here, I&#8217;m defining function called <code>string-to-list</code> that takes a string as an argument. It goes through the string and adds each character in the string to a list. Here it is in action:</p>
<pre>CL-USER&gt; (string-to-list "hello")
(#\h #\e #\l #\l #\o)</pre>
<p>Why the pound signs and slashes before each letter? I wish I could tell you. I don&#8217;t understand that part yet.</p>
<p>Now that I have my string in a list format that&#8217;s easier to deal with, I can do some interesting things with it, like use Lisp&#8217;s <code>FIND </code>function to see whether a string contains a certain character:</p>
<pre>CL-USER&gt; (find #\h (string-to-list "hello"))
#\h
CL-USER&gt; (find #\q (string-to-list "hello"))
NIL
CL-USER&gt;</pre>
<p>The <code>FIND </code>function will return the value of the item of interest if the item is found, or <code>NIL </code>if it&#8217;s not found. I decided to use <code>find </code>in a function to tell me whether or not a letter is a vowel:</p>
<pre>(defun is-vowel (char)
  (if (find char "aeiou") t))</pre>
<p>Let&#8217;s see if it works:</p>
<pre>CL-USER&gt; (is-vowel #\a)
T
CL-USER&gt; (is-vowel #\b)
NIL
CL-USER&gt; (is-vowel #\u)
T
CL-USER&gt; (is-vowel #\d)
NIL
CL-USER&gt;</pre>
<p>Yup. But since T and NIL aren&#8217;t very meaningful to the average person, I wrote a more function with more verbose output:</p>
<pre>(defun letter-type (char)
  (if (is-vowel char) "vowel" "consonant"))</pre>
<p>Pretty simple. Let&#8217;s try it out:</p>
<pre>CL-USER&gt; (letter-type #\a)
"vowel"
CL-USER&gt; (letter-type #\b)
"consonant"
CL-USER&gt; (letter-type #\c)
"consonant"
CL-USER&gt;</pre>
<p>Great. That makes it pretty easy to write the function that tells us whether each letter in a word is a consonant or a vowel. Since we already know how to loop through a string from <code>string-to-list </code>and we have a function that tells us whether a character is a consonant or vowel, we can just put those two ideas together:</p>
<pre>(defun analyze-word (word-string)
  (loop for char across word-string collect (letter-type char)))</pre>
<p>Let&#8217;s try it out with a few words:</p>
<pre>CL-USER&gt; (analyze-word "does")
("consonant" "vowel" "vowel" "consonant")
CL-USER&gt; (analyze-word "it")
("vowel" "consonant")
CL-USER&gt; (analyze-word "work")
("consonant" "vowel" "consonant" "consonant")
CL-USER&gt;</pre>
<p>Seems to work perfectly. If course, we conveniently avoided the tricky letter <em>y</em>, but that&#8217;s beyond the scope of what I&#8217;m willing to do with my first Lisp program.</p>
<p>Hopefully my next Lisp example will be more cohesive and informed. I just wanted to see what I could jump right in without really knowing anything. In the meantime, I&#8217;m going to keep reading <a href="http://www.amazon.com/gp/product/1590592395?ie=UTF8&amp;tag=jasonswettnet-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1590592395">Practical Common Lisp</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonswett.net/my-first-lisp-program/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
