chancery/usage/index.html @ fdfd0925e959

cl-pcg: Update site.
author Steve Losh <steve@stevelosh.com>
date Thu, 23 Mar 2017 13:56:10 +0000
parents c448037d3088
children c8d216ae9ab0
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>Usage / Chancery</title>
        <link rel="stylesheet" href="../_dmedia/pygments-clean.css"/>
        <link rel="stylesheet/less" type="text/css" href="../_dmedia/style.less"/>
        <script src="../_dmedia/less.js" type="text/javascript">
        </script>
    </head>
    <body class="content">
        <div class="wrap">
            <header><h1><a href="..">Chancery</a></h1></header>
                <div class="markdown">
<h1 id="usage"><a href="">Usage</a></h1><p>Chancery is a library for procedurally generating text and data in Common
Lisp.  It's heavily inspired by <a href="http://www.crystalcodepalace.com/traceryTut.html">Tracery</a>, and is essentially just some Lispy
syntactic sugar for writing <a href="https://en.wikipedia.org/wiki/Context-free_grammar">grammars</a>.</p>
<div class="toc">
<ul>
<li><a href="#rules">Rules</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="#evaluation">Evaluation</a></li>
<li><a href="#reader-macros">Reader Macros</a></li>
</ul></div>
<h2 id="rules">Rules</h2>
<p>Rules are the core construct Chancery uses to generate data, and can be created
with <code>define-rule</code>:</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">define-rule</span> <span class="nv">color</span>
  <span class="s">"black"</span>
  <span class="s">"white"</span>
  <span class="s">"brown"</span>
  <span class="s">"gray"</span><span class="p">)</span>
</pre></div>


<p>Rules are compiled into vanilla Lisp functions, so you can call them like you
would any other function.</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">10</span>
      <span class="ss">:collect</span> <span class="p">(</span><span class="nb">list</span> <span class="p">(</span><span class="nv">color</span><span class="p">)</span> <span class="p">(</span><span class="nv">animal</span><span class="p">)))</span>
<span class="c1">; =&gt;</span>
<span class="p">((</span><span class="s">"gray"</span> <span class="s">"dog"</span><span class="p">)</span> <span class="p">(</span><span class="s">"white"</span> <span class="s">"mouse"</span><span class="p">)</span> <span class="p">(</span><span class="s">"gray"</span> <span class="s">"dog"</span><span class="p">)</span>
 <span class="p">(</span><span class="s">"black"</span> <span class="s">"mouse"</span><span class="p">)</span> <span class="p">(</span><span class="s">"gray"</span> <span class="s">"cat"</span><span class="p">)</span> <span class="p">(</span><span class="s">"gray"</span> <span class="s">"cat"</span><span class="p">)</span>
 <span class="p">(</span><span class="s">"white"</span> <span class="s">"mouse"</span><span class="p">)</span> <span class="p">(</span><span class="s">"white"</span> <span class="s">"dog"</span><span class="p">)</span> <span class="p">(</span><span class="s">"gray"</span> <span class="s">"mouse"</span><span class="p">)</span>
 <span class="p">(</span><span class="s">"brown"</span> <span class="s">"cat"</span><span class="p">))</span>
</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>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>
  <span class="s">"whiskers"</span><span class="p">)</span>

<span class="p">(</span><span class="nv">define-rule</span> <span class="nv">dog-name</span>
  <span class="s">"spot"</span>
  <span class="s">"fido"</span>
  <span class="s">"lassie"</span><span class="p">)</span>

<span class="p">(</span><span class="nv">define-rule</span> <span class="nv">animal-name</span>
  <span class="nv">cat-name</span>
  <span class="nv">dog-name</span><span class="p">)</span>

<span class="p">(</span><span class="nb">loop</span> <span class="ss">:repeat</span> <span class="mi">10</span> <span class="ss">:collect</span> <span class="p">(</span><span class="nv">animal-name</span><span class="p">))</span>
<span class="c1">; =&gt;</span>
<span class="p">(</span><span class="s">"spot"</span> <span class="s">"spot"</span> <span class="s">"fido"</span> <span class="s">"fluffy"</span> <span class="s">"fido"</span> <span class="s">"spot"</span>
 <span class="s">"fluffy"</span> <span class="s">"spot"</span> <span class="s">"spot"</span> <span class="s">"lassie"</span><span class="p">)</span>
</pre></div>


<p>Lists recursively evaluate their members and return the result as a fresh list:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="nv">pet</span>
  <span class="p">(</span><span class="nv">cat-name</span> <span class="nv">color</span> <span class="ss">:cat</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">dog-name</span> <span class="nv">color</span> <span class="ss">:dog</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">pet</span><span class="p">))</span>
<span class="c1">; =&gt;</span>
<span class="p">((</span><span class="s">"fluffy"</span> <span class="s">"brown"</span> <span class="ss">:CAT</span><span class="p">)</span> <span class="p">(</span><span class="s">"fluffy"</span> <span class="s">"white"</span> <span class="ss">:CAT</span><span class="p">)</span>
 <span class="p">(</span><span class="s">"fido"</span> <span class="s">"brown"</span> <span class="ss">:DOG</span><span class="p">)</span> <span class="p">(</span><span class="s">"lassie"</span> <span class="s">"white"</span> <span class="ss">:DOG</span><span class="p">)</span>
 <span class="p">(</span><span class="s">"fluffy"</span> <span class="s">"black"</span> <span class="ss">:CAT</span><span class="p">))</span>
</pre></div>


<p>If you want to return a literal symbol or list from a rule you can <code>quote</code> it:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="nv">foo</span>
  <span class="ss">'a</span>
  <span class="o">'</span><span class="p">(</span><span class="nv">x</span> <span class="nv">y</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">foo</span><span class="p">))</span>
<span class="c1">; =&gt;</span>
<span class="p">(</span><span class="nv">A</span> <span class="p">(</span><span class="nv">X</span> <span class="nv">Y</span><span class="p">)</span> <span class="p">(</span><span class="nv">X</span> <span class="nv">Y</span><span class="p">)</span> <span class="nv">A</span> <span class="nv">A</span><span class="p">)</span>
</pre></div>


<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
more often than others:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="p">(</span><span class="nv">metal</span> <span class="ss">:distribution</span> <span class="ss">:weighted</span><span class="p">)</span>
  <span class="p">(</span><span class="mi">10</span> <span class="nv">iron</span><span class="p">)</span>
  <span class="p">(</span><span class="mi">5</span> <span class="nv">steel</span><span class="p">)</span>
  <span class="p">(</span><span class="mi">2</span> <span class="nv">silver</span><span class="p">)</span>
  <span class="p">(</span><span class="mi">1</span> <span class="nv">gold</span><span class="p">)</span>
  <span class="p">(</span><span class="mi">1</span> <span class="nv">platinum</span><span class="p">))</span>
</pre></div>


<p>Weighting each term by hand can be tedious.  Chancery can automatically
calculate weights based on the order of the body terms according to <a href="https://en.wikipedia.org/wiki/Zipf's_law">Zipf's
law</a>:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-rule</span> <span class="p">(</span><span class="nv">armor-type</span> <span class="ss">:distribution</span> <span class="ss">:zipf</span><span class="p">)</span>
  <span class="ss">:scale-mail</span>
  <span class="ss">:chain-mail</span>
  <span class="ss">:banded-mail</span>
  <span class="ss">:plate-mail</span><span class="p">)</span>
</pre></div>


<h2 id="text-generation">Text Generation</h2>
<h2 id="modifiers">Modifiers</h2>
<h2 id="evaluation">Evaluation</h2>
<h2 id="reader-macros">Reader Macros</h2>
                </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>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-15328874-3', 'auto');
  ga('send', 'pageview');

</script></footer>
        </div>
    </body>
</html>