c8d216ae9ab0

chancery: Update site.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Fri, 03 Nov 2017 01:05:46 -0400
parents 3895fb764d10
children efd3010b387b
branches/tags (none)
files chancery/index.html chancery/reference/index.html chancery/usage/index.html

Changes

--- a/chancery/index.html	Sun Oct 22 14:58:02 2017 -0400
+++ b/chancery/index.html	Fri Nov 03 01:05:46 2017 -0400
@@ -15,7 +15,7 @@
 <p>Chancery is a library for procedurally generating text and data in Common
 Lisp.  It's heavily inspired by <a href="http://tracery.io/">Tracery</a>.</p>
 <ul>
-<li><strong>License:</strong> MIT</li>
+<li><strong>License:</strong> MIT/X11</li>
 <li><strong>Documentation:</strong> <a href="https://sjl.bitbucket.io/chancery/">https://sjl.bitbucket.io/chancery/</a></li>
 <li><strong>Mercurial:</strong> <a href="http://bitbucket.org/sjl/chancery/">http://bitbucket.org/sjl/chancery/</a></li>
 <li><strong>Git:</strong> <a href="http://github.com/sjl/chancery/">http://github.com/sjl/chancery/</a></li>
--- a/chancery/reference/index.html	Sun Oct 22 14:58:02 2017 -0400
+++ b/chancery/reference/index.html	Fri Nov 03 01:05:46 2017 -0400
@@ -20,19 +20,24 @@
 <div class="toc">
 <ul>
 <li><a href="#package-chancery">Package CHANCERY</a><ul>
+<li><a href="#random-variable">*RANDOM* (variable)</a></li>
 <li><a href="#a-function">A (function)</a></li>
 <li><a href="#cap-function">CAP (function)</a></li>
 <li><a href="#cap-all-function">CAP-ALL (function)</a></li>
+<li><a href="#create-rule-function">CREATE-RULE (function)</a></li>
+<li><a href="#create-string-function">CREATE-STRING (function)</a></li>
 <li><a href="#define-rule-macro">DEFINE-RULE (macro)</a></li>
 <li><a href="#define-string-macro">DEFINE-STRING (macro)</a></li>
-<li><a href="#gen-macro">GEN (macro)</a></li>
-<li><a href="#gen-string-macro">GEN-STRING (macro)</a></li>
+<li><a href="#generate-macro">GENERATE (macro)</a></li>
+<li><a href="#generate-string-macro">GENERATE-STRING (macro)</a></li>
 <li><a href="#pos-function">POS (function)</a></li>
 <li><a href="#s-function">S (function)</a></li>
 </ul>
 </li>
 </ul></div>
 <h2 id="package-chancery">Package <code>CHANCERY</code></h2>
+<h3 id="random-variable"><code>*RANDOM*</code> (variable)</h3>
+<p>The random number generation function to use (default: <code>CL:RANDOM</code>).</p>
 <h3 id="a-function"><code>A</code> (function)</h3>
 <div class="codehilite"><pre><span/>(A STRING)
 </pre></div>
@@ -51,28 +56,142 @@
 
 
 <p>Capitalize each word of <code>string</code>.</p>
+<h3 id="create-rule-function"><code>CREATE-RULE</code> (function)</h3>
+<div class="codehilite"><pre><span/>(CREATE-RULE EXPRESSIONS &amp;REST OPTIONS)
+</pre></div>
+
+
+<p>Return a function that will return random elements of <code>expressions</code>.</p>
+<p><code>options</code> should be of the form:</p>
+<div class="codehilite"><pre><span/>(&amp;key documentation (distribution :uniform) (arguments '()))
+</pre></div>
+
+
+<p><code>documentation</code> will be used as a docstring for the resulting function.</p>
+<p><code>distribution</code> denotes the distribution of elements returned.</p>
+<p><code>arguments</code> is the arglist of the resulting function.</p>
+<p>Examples:</p>
+<div class="codehilite"><pre><span/>(create-rule (list :blue :red :green))
+
+(create-rule (list :copper :silver :gold :platinum)
+  :documentation "Return a random metal."
+  :distribution :zipf)
+</pre></div>
+
+
+<p>See the full documentation for more information.</p>
+<h3 id="create-string-function"><code>CREATE-STRING</code> (function)</h3>
+<div class="codehilite"><pre><span/>(CREATE-STRING EXPRESSIONS &amp;REST OPTIONS)
+</pre></div>
+
+
+<p>Return a function that will return random stringified elements of <code>expressions</code>.</p>
+<p><code>options</code> should be of the form:</p>
+<div class="codehilite"><pre><span/>(&amp;key documentation (distribution :uniform) (arguments '()))
+</pre></div>
+
+
+<p><code>documentation</code> will be used as a docstring for the resulting function.</p>
+<p><code>distribution</code> denotes the distribution of elements returned.</p>
+<p><code>arguments</code> is the arglist of the resulting function.</p>
+<p>Examples:</p>
+<div class="codehilite"><pre><span/>(create-string (list "white" "gray" "black"))
+
+(create-string '((100 (color "cat"))
+                 (100 (color "dog"))
+                 (100 (color "dragon")))
+  :distribution :weighted)
+</pre></div>
+
+
+<p>See the full documentation for more information.</p>
 <h3 id="define-rule-macro"><code>DEFINE-RULE</code> (macro)</h3>
 <div class="codehilite"><pre><span/>(DEFINE-RULE NAME-AND-OPTIONS &amp;REST EXPRESSIONS)
 </pre></div>
 
 
+<p>Define a function that will return random elements of <code>expressions</code>.</p>
+<p><code>name-and-options</code> should be of the form:</p>
+<div class="codehilite"><pre><span/>(name &amp;key documentation (distribution :uniform) (arguments '()))
+</pre></div>
+
+
+<p>If no options are needed a bare symbol can be given.</p>
+<p><code>name</code> is the symbol under which the resulting function will be defined.</p>
+<p><code>documentation</code> will be used as a docstring for the resulting function.</p>
+<p><code>distribution</code> denotes the distribution of elements returned.</p>
+<p><code>arguments</code> is the arglist of the resulting function.</p>
+<p>Examples:</p>
+<div class="codehilite"><pre><span/>(define-rule color
+  :blue
+  :green
+  :red)
+
+(define-rule (metal :documentation "Return a random metal."
+                    :distribution :zipf)
+  :copper
+  :silver
+  :gold
+  :platinum)
+</pre></div>
+
+
+<p>See the full documentation for more information.</p>
 <h3 id="define-string-macro"><code>DEFINE-STRING</code> (macro)</h3>
 <div class="codehilite"><pre><span/>(DEFINE-STRING NAME-AND-OPTIONS &amp;REST EXPRESSIONS)
 </pre></div>
 
 
-<h3 id="gen-macro"><code>GEN</code> (macro)</h3>
-<div class="codehilite"><pre><span/>(GEN EXPRESSION)
+<p>Define a function that will return random stringified elements of <code>expressions</code>.</p>
+<p><code>name-and-options</code> should be of the form:</p>
+<div class="codehilite"><pre><span/>(name &amp;key documentation (distribution :uniform) (arguments '()))
+</pre></div>
+
+
+<p>If no options are needed a bare symbol can be given.</p>
+<p><code>name</code> is the symbol under which the resulting function will be defined.</p>
+<p><code>documentation</code> will be used as a docstring for the resulting function.</p>
+<p><code>distribution</code> denotes the distribution of elements returned.</p>
+<p><code>arguments</code> is the arglist of the resulting function.</p>
+<p>Examples:</p>
+<div class="codehilite"><pre><span/>(define-string color "white" "gray" "black")
+
+(define-string (animal :distribution :weighted)
+  (100 (color "cat"))
+  (100 (color "dog"))
+  (100 (color "dragon")))
+</pre></div>
+
+
+<p>See the full documentation for more information.</p>
+<h3 id="generate-macro"><code>GENERATE</code> (macro)</h3>
+<div class="codehilite"><pre><span/>(GENERATE EXPRESSION)
 </pre></div>
 
 
 <p>Generate a single Chancery expression.</p>
-<h3 id="gen-string-macro"><code>GEN-STRING</code> (macro)</h3>
-<div class="codehilite"><pre><span/>(GEN-STRING EXPRESSION)
+<p>Example:</p>
+<div class="codehilite"><pre><span/>(define-rule x 1 2 3)
+
+(generate (x x x))
+; =&gt; (1 3 1)
 </pre></div>
 
 
-<p>Generate a single Chancery string expression.</p>
+<h3 id="generate-string-macro"><code>GENERATE-STRING</code> (macro)</h3>
+<div class="codehilite"><pre><span/>(GENERATE-STRING EXPRESSION)
+</pre></div>
+
+
+<p>Generate and stringify a single Chancery string expression.</p>
+<p>Example:</p>
+<div class="codehilite"><pre><span/>(define-string x 1 2 3)
+
+(generate-string (x x x))
+; =&gt; "1 3 1"
+</pre></div>
+
+
 <h3 id="pos-function"><code>POS</code> (function)</h3>
 <div class="codehilite"><pre><span/>(POS STRING)
 </pre></div>
--- a/chancery/usage/index.html	Sun Oct 22 14:58:02 2017 -0400
+++ b/chancery/usage/index.html	Fri Nov 03 01:05:46 2017 -0400
@@ -18,11 +18,15 @@
 <div class="toc">
 <ul>
 <li><a href="#rules">Rules</a></li>
+<li><a href="#text-generation">Text Generation</a></li>
 <li><a href="#distributions">Distributions</a></li>
-<li><a href="#text-generation">Text Generation</a></li>
-<li><a href="#modifiers">Modifiers</a></li>
+<li><a href="#single-generation">Single Generation</a></li>
+<li><a href="#string-modifiers">String Modifiers</a></li>
 <li><a href="#evaluation">Evaluation</a></li>
 <li><a href="#reader-macros">Reader Macros</a></li>
+<li><a href="#runtime-rule-creation">Runtime Rule Creation</a></li>
+<li><a href="#tips">Tips</a></li>
+<li><a href="#examples">Examples</a></li>
 </ul></div>
 <h2 id="rules">Rules</h2>
 <p>Rules are the core construct Chancery uses to generate data, and can be created
@@ -52,9 +56,9 @@
 </pre></div>
 
 
-<p>Basic rules select one of their body terms at random and evaluate it.  Most
-kinds of objects (e.g. strings, keywords, numbers) evaluate to themselves, but
-there are a few exceptions.</p>
+<p>Basic rules select one of their body terms at random and evaluate it according
+to some special rules.  Most kinds of objects (e.g. strings, keywords, numbers)
+evaluate to themselves, but there are a few exceptions.</p>
 <p>Symbols evaluate to <code>(funcall 'symbol)</code>, so rules can easily call other rules:</p>
 <div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="nv">cat-name</span>
   <span class="s">"fluffy"</span>
@@ -100,6 +104,54 @@
 </pre></div>
 
 
+<h2 id="text-generation">Text Generation</h2>
+<p>Grammars are often used to generate strings, and Chancery has a few extra bits
+of syntactic sugar to make it easy to generate readable text.  <code>define-string</code>
+can be used to define a rule function that stringifies its result before
+returning it:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-string</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"dog"</span> <span class="s">"mouse"</span><span class="p">)</span>
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">name</span> <span class="s">"Alice"</span> <span class="s">"Bob"</span> <span class="s">"Carol"</span><span class="p">)</span>
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">place</span> <span class="s">"mountain"</span> <span class="s">"forest"</span> <span class="s">"river"</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">story</span>
+  <span class="p">(</span><span class="nv">name</span> <span class="s">"the"</span> <span class="nv">animal</span> <span class="s">"went to the"</span> <span class="nv">place</span><span class="p">)</span>
+  <span class="p">(</span><span class="s">"a friendly"</span> <span class="nv">animal</span> <span class="s">"lived near a"</span> <span class="nv">place</span><span class="p">))</span>
+
+<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">5</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">story</span><span class="p">))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; ("Alice the mouse went to the river"</span>
+<span class="c1">;  "Bob the cat went to the forest"</span>
+<span class="c1">;  "a friendly mouse lived near a river"</span>
+<span class="c1">;  "a friendly cat lived near a forest"</span>
+<span class="c1">;  "Bob the cat went to the river")</span>
+</pre></div>
+
+
+<p><code>define-string</code> works the same way as <code>define-rule</code>, except that the evaluation
+of certain items is slightly different.</p>
+<p>Strings evaluate to themselves.  <code>NIL</code> evaluates to an empty string.  Other
+non-keyword symbols evaluate to procedure calls, as with <code>define-rule</code>.</p>
+<p>Lists evaluate their arguments and concatenate them with one <code>#\Space</code> between
+each.  If you don't want a space between two items you can use the special
+symbol <code>:.</code> to suppress it:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-string</span> <span class="nv">foo</span> <span class="s">"x"</span> <span class="s">"y"</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">with-spaces</span>
+  <span class="p">(</span><span class="nv">foo</span> <span class="nv">foo</span> <span class="nv">foo</span><span class="p">))</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">without-spaces</span>
+  <span class="p">(</span><span class="nv">foo</span> <span class="ss">:.</span> <span class="nv">foo</span> <span class="ss">:.</span> <span class="nv">foo</span><span class="p">))</span>
+
+<span class="p">(</span><span class="nv">with-spaces</span><span class="p">)</span>    <span class="c1">; =&gt; "x x y"</span>
+<span class="p">(</span><span class="nv">without-spaces</span><span class="p">)</span> <span class="c1">; =&gt; "xyx"</span>
+</pre></div>
+
+
+<p>The special form <code>(quote ...)</code> evaluates to its argument, <em>without</em> stringifying
+it.  Note that this is one case where a <code>define-string</code> could return something
+that isn't a string, so use it with care.</p>
+<p>Everything else (except vectors, which we'll talk about shortly) evaluates to
+the result of calling <code>princ-to-string</code> on it.</p>
 <h2 id="distributions">Distributions</h2>
 <p>By default each body term in a rule has an equal chance of being chosen.</p>
 <p>Chancery also includes support for weighting the terms so some will be chosen
@@ -124,10 +176,240 @@
 </pre></div>
 
 
-<h2 id="text-generation">Text Generation</h2>
-<h2 id="modifiers">Modifiers</h2>
+<p>The Zipf distribution can itself take an argument <code>exponent</code>, which is the
+exponent characterizing the distribution.  The default is <code>1.0</code>, and larger
+exponents will result in the earlier terms being chosen more often:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="p">(</span><span class="nv">foo</span> <span class="ss">:distribution</span> <span class="ss">:zipf</span><span class="p">)</span>
+  <span class="ss">:a</span> <span class="ss">:b</span> <span class="ss">:c</span> <span class="ss">:d</span> <span class="ss">:e</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-rule</span> <span class="p">(</span><span class="nv">bar</span> <span class="ss">:distribution</span> <span class="p">(</span><span class="ss">:zipf</span> <span class="ss">:exponent</span> <span class="mf">3.0</span><span class="p">))</span>
+  <span class="ss">:a</span> <span class="ss">:b</span> <span class="ss">:c</span> <span class="ss">:d</span> <span class="ss">:e</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-rule</span> <span class="p">(</span><span class="nv">baz</span> <span class="ss">:distribution</span> <span class="p">(</span><span class="ss">:zipf</span> <span class="ss">:exponent</span> <span class="mf">0.25</span><span class="p">))</span>
+  <span class="ss">:a</span> <span class="ss">:b</span> <span class="ss">:c</span> <span class="ss">:d</span> <span class="ss">:e</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nb">count</span> <span class="ss">:a</span> <span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">1000</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">foo</span><span class="p">)))</span>
+<span class="c1">; =&gt; 413</span>
+
+<span class="p">(</span><span class="nb">count</span> <span class="ss">:a</span> <span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">1000</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">bar</span><span class="p">)))</span>
+<span class="c1">; =&gt; 831</span>
+
+<span class="p">(</span><span class="nb">count</span> <span class="ss">:a</span> <span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">1000</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">baz</span><span class="p">)))</span>
+<span class="c1">; =&gt; 257</span>
+</pre></div>
+
+
+<h2 id="single-generation">Single Generation</h2>
+<p>Sometimes it can be handy to evaluate a Chancery expression without defining an
+actual rule.  The <code>generate</code> macro evaluates vanilla Chancery expressions, and
+<code>generate-string</code> evaluates Chancery string expressions:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="nv">x</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span><span class="p">)</span>
+<span class="p">(</span><span class="nv">define-rule</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"dog"</span> <span class="s">"mouse"</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">generate</span> <span class="ss">:foo</span><span class="p">)</span>    <span class="c1">; =&gt; :FOO</span>
+<span class="p">(</span><span class="nv">generate</span> <span class="nv">x</span><span class="p">)</span>       <span class="c1">; =&gt; 2</span>
+<span class="p">(</span><span class="nv">generate</span> <span class="p">(</span><span class="nv">x</span> <span class="nv">x</span> <span class="nv">x</span><span class="p">))</span> <span class="c1">; =&gt; (2 2 1)</span>
+
+<span class="p">(</span><span class="nv">generate-string</span> <span class="ss">:foo</span><span class="p">)</span>             <span class="c1">; =&gt; "FOO"</span>
+<span class="p">(</span><span class="nv">generate-string</span> <span class="nv">x</span><span class="p">)</span>                <span class="c1">; =&gt; "1"</span>
+<span class="p">(</span><span class="nv">generate-string</span> <span class="p">(</span><span class="s">"fuzzy"</span> <span class="nv">animal</span><span class="p">))</span> <span class="c1">; =&gt; "fuzzy mouse"</span>
+</pre></div>
+
+
+<h2 id="string-modifiers">String Modifiers</h2>
+<p>Procedurally generating readable text can be tricky, so Chancery includes some
+syntax and a few helper functions to make your life easier.</p>
+<p>Inside a <code>define-string</code> vectors are evaluated specially.  The first element of
+the vector is evaluated as usual in <code>define-string</code>.  All remaining elements in
+the vector are treated as function names, and the result is threaded through
+each function in turn.  Finally, the resulting value will be stringified. For
+example:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"dog"</span> <span class="s">"mouse"</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">generate-string</span> <span class="p">(</span><span class="s">"the"</span> <span class="nv">animal</span> <span class="s">"ran"</span><span class="p">))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; "the cat ran"</span>
+
+<span class="p">(</span><span class="nv">generate-string</span> <span class="p">(</span><span class="s">"the"</span> <span class="o">#(</span><span class="nv">animal</span> <span class="nb">string-upcase</span><span class="p">)</span> <span class="s">"ran"</span><span class="p">))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; "the MOUSE ran"</span>
+</pre></div>
+
+
+<p>Chancery defines a few helpful functions for generating English text:</p>
+<ul>
+<li><code>s</code> pluralizes its argument.</li>
+<li><code>a</code> adds an indefinite article ("a" or "an") to the front of its argument.</li>
+<li><code>cap</code> capitalizes the first letter of its argument.</li>
+<li><code>cap-all</code> capitalizes each word in its argument.)</li>
+<li><code>pos</code> makes its argument possessive by adding an apostrophe (and possibly an s).</li>
+</ul>
+<p>These are just normal Lisp functions that happen to be useful as modifiers:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-string</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"aardvark"</span> <span class="s">"fly"</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">5</span>
+      <span class="ss">:collect</span> <span class="p">(</span><span class="nv">generate-string</span>
+                 <span class="p">(</span><span class="s">"a bunch of"</span> <span class="o">#(</span><span class="nv">animal</span> <span class="nv">s</span><span class="p">))))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; ("a bunch of flies" "a bunch of flies" "a bunch of aardvarks"</span>
+<span class="c1">;  "a bunch of cats" "a bunch of aardvarks")</span>
+
+<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">5</span>
+      <span class="ss">:collect</span> <span class="p">(</span><span class="nv">generate-string</span>
+                 <span class="p">(</span><span class="o">#(</span><span class="nv">animal</span> <span class="nv">a</span> <span class="nv">cap</span><span class="p">)</span> <span class="s">"is a good pet"</span><span class="p">)))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; ("A cat is a good pet" "A fly is a good pet" "A fly is a good pet"</span>
+<span class="c1">;  "A cat is a good pet" "An aardvark is a good pet")</span>
+</pre></div>
+
+
+<p>English is a messy language.  Pull requests to improve these functions (or add
+more useful ones) are welcome.</p>
 <h2 id="evaluation">Evaluation</h2>
+<p>Sometimes it can be useful to switch out of "Chancery evaluation" and back into
+normal Lisp evaluation.  The <code>(eval ...)</code> special form can be used to do this in
+Chancery rules and string rules:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="nv">treasure</span>
+  <span class="ss">:weapon</span>
+  <span class="ss">:armor</span>
+  <span class="p">((</span><span class="nb">eval</span> <span class="p">(</span><span class="nb">random</span> <span class="mi">100</span><span class="p">))</span> <span class="ss">:gold</span><span class="p">))</span>
+
+<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">5</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">treasure</span><span class="p">))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; ((93 :GOLD)</span>
+<span class="c1">;  :WEAPON</span>
+<span class="c1">;  (83 :GOLD)</span>
+<span class="c1">;  :WEAPON</span>
+<span class="c1">;  :ARMOR)</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"dog"</span><span class="p">)</span>
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">story</span>
+  <span class="p">(</span><span class="s">"The"</span> <span class="nv">animal</span> <span class="s">"had"</span> <span class="p">(</span><span class="nb">eval</span> <span class="p">(</span><span class="nb">+</span> <span class="mi">2</span> <span class="p">(</span><span class="nb">random</span> <span class="mi">3</span><span class="p">)))</span> <span class="s">"friends."</span><span class="p">))</span>
+
+<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">5</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">story</span><span class="p">))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; ("The dog had 3 friends." "The cat had 2 friends." "The dog had 3 friends."</span>
+<span class="c1">;  "The cat had 4 friends." "The dog had 2 friends.")</span>
+</pre></div>
+
+
+<p>You can think of <code>eval</code> and <code>generate</code> as two sides of the same coin, kind of
+like quasiquote's backquote and comma.  <code>eval</code> flips from Chancery evaluation to
+Lisp evaluation, and <code>generate</code> flips in the other direction.</p>
 <h2 id="reader-macros">Reader Macros</h2>
+<p>Chancery provides four reader macros you can use to make defining grammars
+even more concise.  It uses <a href="https://common-lisp.net/project/named-readtables/">named-readtables</a> to keep them safely stashed
+away unless you want them.</p>
+<p>The first reader macro is <code>[...]</code> to replace the standard vector <code>#(...)</code>
+syntax, to make string modifiers stand out more:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">named-readtables:in-readtable</span> <span class="ss">:chancery</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"dog"</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">generate-string</span> <span class="p">(</span><span class="s">"a few"</span> <span class="nv">[animal</span> <span class="nv">s]</span><span class="p">))</span>
+<span class="c1">; =&gt; "a few cats"</span>
+</pre></div>
+
+
+<p>The reader macro <code>!form</code> expands to <code>(eval form)</code>:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">named-readtables:in-readtable</span> <span class="ss">:chancery</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-rule</span> <span class="nv">treasure</span>
+  <span class="ss">:weapon</span>
+  <span class="ss">:armor</span>
+  <span class="p">(</span><span class="nv">!</span><span class="p">(</span><span class="nb">random</span> <span class="mi">100</span><span class="p">)</span> <span class="ss">:gold</span><span class="p">))</span>
+
+<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">5</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">treasure</span><span class="p">))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; (:ARMOR (53 :GOLD) (49 :GOLD) :ARMOR :WEAPON)</span>
+</pre></div>
+
+
+<p>The reader macro <code>@form</code> expands to <code>(generate form)</code>, and <code>$form</code> expands to
+<code>(generate-string form)</code>.  Note that none of th</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">named-readtables:in-readtable</span> <span class="ss">:chancery</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"dog"</span><span class="p">)</span>
+
+<span class="nv">$</span><span class="p">(</span><span class="s">"the"</span> <span class="nv">animal</span> <span class="s">"ran"</span><span class="p">)</span>
+<span class="c1">; =&gt; "the cat ran"</span>
+</pre></div>
+
+
+<p>Together these let you jump in and out of Chancery-style evaluation as needed:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">named-readtables:in-readtable</span> <span class="ss">:chancery</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">animal</span> <span class="s">"cat"</span> <span class="s">"dog"</span><span class="p">)</span>
+
+<span class="p">(</span><span class="nv">define-string</span> <span class="nv">story</span>
+  <span class="p">(</span><span class="s">"the"</span> <span class="nv">animal</span> <span class="s">"went to sleep"</span><span class="p">)</span>
+  <span class="nv">!</span><span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">pet</span> <span class="p">(</span><span class="nv">animal</span><span class="p">)))</span>
+     <span class="nv">$</span><span class="p">(</span><span class="s">"the"</span> <span class="nv">!pet</span> <span class="s">"was a good"</span> <span class="nv">!pet</span><span class="p">)))</span>
+
+<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">4</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">story</span><span class="p">))</span>
+<span class="c1">; =&gt;</span>
+<span class="c1">; ("the dog was a good dog" "the cat was a good cat"</span>
+<span class="c1">;  "the dog was a good dog" "the cat went to sleep")</span>
+</pre></div>
+
+
+<p>This last example is a little tricky, but it helps to think of <code>$</code> and <code>@</code> as
+quasiquote's backquote, and <code>!</code> as comma.  Flipping back and forth between Lisp
+and Chancery can let you define some really interesting grammars.</p>
+<h2 id="runtime-rule-creation">Runtime Rule Creation</h2>
+<p>All of the Chancery things we've been using so far have been macros.  If you
+want to create rules at runtime you can use their function counterparts:</p>
+<ul>
+<li><code>create-rule</code> takes a list of expressions and options, and returns a rule
+  function.</li>
+<li><code>create-string</code> takes a list of expressions and options, and returns a string
+  function.</li>
+<li><code>invoke-generate</code> takes an expression and evaluates it.</li>
+<li><code>invoke-generate-string</code> takes an expression and evaluates it and stringifies
+  the result.</li>
+</ul>
+<p>For example:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="n">define</span><span class="o">-</span><span class="n">rule</span> <span class="nl">foo</span> <span class="p">:</span><span class="nl">a</span> <span class="p">:</span><span class="nl">b</span> <span class="p">:</span><span class="n">c</span><span class="p">)</span>
+<span class="p">(</span><span class="n">foo</span><span class="p">)</span>
+<span class="p">;</span> <span class="n">versus</span>
+<span class="p">(</span><span class="n">funcall</span> <span class="p">(</span><span class="n">create</span><span class="o">-</span><span class="n">rule</span> <span class="p">(</span><span class="nl">list</span> <span class="p">:</span><span class="nl">a</span> <span class="p">:</span><span class="nl">b</span> <span class="p">:</span><span class="n">c</span><span class="p">)))</span>
+
+<span class="p">(</span><span class="n">define</span><span class="o">-</span><span class="n">string</span> <span class="p">(</span><span class="nl">bar</span> <span class="p">:</span><span class="nl">distribution</span> <span class="p">:</span><span class="n">zipf</span><span class="p">)</span>
+  <span class="p">(</span><span class="s">"one"</span> <span class="n">foo</span><span class="p">)</span>
+  <span class="p">(</span><span class="s">"two"</span> <span class="p">[</span><span class="n">foo</span> <span class="n">s</span><span class="p">]))</span>
+<span class="p">(</span><span class="n">bar</span><span class="p">)</span>
+<span class="p">;</span> <span class="n">versus</span>
+<span class="p">(</span><span class="n">funcall</span> <span class="p">(</span><span class="n">create</span><span class="o">-</span><span class="n">string</span> <span class="p">(</span><span class="n">list</span> <span class="err">'</span><span class="p">(</span><span class="s">"one"</span> <span class="n">foo</span><span class="p">)</span>
+                              <span class="err">'</span><span class="p">(</span><span class="s">"two"</span> <span class="p">[</span><span class="n">foo</span> <span class="n">s</span><span class="p">]))</span>
+           <span class="o">:</span><span class="nl">distribution</span> <span class="p">:</span><span class="n">zipf</span><span class="p">))</span>
+</pre></div>
+
+
+<h2 id="tips">Tips</h2>
+<p>Chancery aims to be a very thin layer on top of Lisp.  Chancery rules are just
+vanilla Lisp functions—you can <code>describe</code> them, <code>disassemble</code> them, <code>trace</code>
+them, <code>funcall</code> them, and anything else you might normally want to do with
+functions.  Similarly, Chancery string modifiers are just unary functions—you
+can create your own, or even use built-in Lisp functions like <code>string-upcase</code>.</p>
+<p>Remember that you can flip back and forth between Chancery evaluation and normal
+Lisp evaluation.  Sometimes it's easier to just do a quick <code>!(if foo then else)</code>
+than to make Yet Another Rule.  Use your own judgement to determine when a rule
+is getting too hairy and needs to be split into simpler parts, just like you
+would for any other Lisp function.</p>
+<h2 id="examples">Examples</h2>
+<p>If you want some less trivial examples than the ones seen here you might want to
+take a look at some of the Twitter bots I've built with Chancery:</p>
+<ul>
+<li><a href="http://twitter.com/git_commands">@git_commands</a>
+  (<a href="https://github.com/sjl/magitek/blob/master/src/robots/git-commands.lisp">code</a>)
+  tweets procedurally-generated Git command summaries.</li>
+<li><a href="http://twitter.com/lisp_talks">@lisp_talks</a>
+  (<a href="https://github.com/sjl/magitek/blob/master/src/robots/lisp-talks.lisp">code</a>)
+  tweets random topics for Lisp talks.</li>
+<li><a href="http://twitter.com/rpg_shopkeeper">@rpg_shopkeeper</a>
+  (<a href="https://github.com/sjl/magitek/blob/master/src/robots/rpg-shopkeeper.lisp">code</a>)
+  generates random fantasy RPG items, and sells them for appropriate prices.</li>
+</ul>
                 </div>
             <footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a> in Reykjavík, Iceland.</i></p>
 <script>