docs/02-usage.markdown @ d6aa232e6306
Add `create-...` functions, clean up RNG system, add a test suite
author |
Steve Losh <steve@stevelosh.com> |
date |
Fri, 23 Jun 2017 13:28:48 +0000 |
parents |
3d06e5b432c9 |
children |
53d4a4db967f |
Usage
=====
Chancery is a library for procedurally generating text and data in Common
Lisp. It's heavily inspired by [Tracery][], and is essentially just some Lispy
syntactic sugar for writing [grammars][cfg].
[Tracery]: http://www.crystalcodepalace.com/traceryTut.html
[cfg]: https://en.wikipedia.org/wiki/Context-free_grammar
[TOC]
Rules
-----
Rules are the core construct Chancery uses to generate data, and can be created
with `define-rule`:
:::lisp
(define-rule animal
"cat"
"dog"
"mouse")
(define-rule color
"black"
"white"
"brown"
"gray")
Rules are compiled into vanilla Lisp functions, so you can call them like you
would any other function.
:::lisp
(loop :repeat 10
:collect (list (color) (animal)))
; =>
(("gray" "dog") ("white" "mouse") ("gray" "dog")
("black" "mouse") ("gray" "cat") ("gray" "cat")
("white" "mouse") ("white" "dog") ("gray" "mouse")
("brown" "cat"))
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.
Symbols evaluate to `(funcall 'symbol)`, so rules can easily call other rules:
:::lisp
(define-rule cat-name
"fluffy"
"whiskers")
(define-rule dog-name
"spot"
"fido"
"lassie")
(define-rule animal-name
cat-name
dog-name)
(loop :repeat 10 :collect (animal-name))
; =>
("spot" "spot" "fido" "fluffy" "fido" "spot"
"fluffy" "spot" "spot" "lassie")
Lists recursively evaluate their members and return the result as a fresh list:
:::lisp
(define-rule pet
(cat-name color :cat)
(dog-name color :dog))
(loop :repeat 5 :collect (pet))
; =>
(("fluffy" "brown" :CAT) ("fluffy" "white" :CAT)
("fido" "brown" :DOG) ("lassie" "white" :DOG)
("fluffy" "black" :CAT))
If you want to return a literal symbol or list from a rule you can `quote` it:
:::lisp
(define-rule foo
'a
'(x y))
(loop :repeat 5 :collect (foo))
; =>
(A (X Y) (X Y) A A)
Distributions
-------------
By default each body term in a rule has an equal chance of being chosen.
Chancery also includes support for weighting the terms so some will be chosen
more often than others:
:::lisp
(define-rule (metal :distribution :weighted)
(10 iron)
(5 steel)
(2 silver)
(1 gold)
(1 platinum))
Weighting each term by hand can be tedious. Chancery can automatically
calculate weights based on the order of the body terms according to [Zipf's
law][zipf]:
:::lisp
(define-rule (armor-type :distribution :zipf)
:scale-mail
:chain-mail
:banded-mail
:plate-mail)
[zipf]: https://en.wikipedia.org/wiki/Zipf's_law
Text Generation
---------------
Modifiers
---------
Evaluation
----------
Reader Macros
-------------