Welcome to TeXCHR (spoken as "tech-cher")! To run the example you just need plain, good-old TeX. Run:
tex example.texThis is based on the Python FreeCHR implementation by Sascha Rechenberger.
I've written this more as a joke than a real piece of good TeX software, you could do a lot better and several macros are now over-generalized (most do not need arguments, as we could just lock a name like \constraints for each program).
The main file is chr.tex, which includes everything desired to get chr for your (plain) TeX project.
Feel free to improve it or to criticize it, I'm open to suggestions.
Allows to use FreeCHR in plain TeX. Every program must be wrapped in \chr{name}{program} (results can be printed directly or stored using \gdef/\xdef).
Basic \Rule{name}{kept-heads,...}{removed-heads,...}{guard}{body}, \Compose{rules,...}, and \Run{constraints,...} with FreeCHR semantics.1
Within the heads, you can use \c to access the current constraint! For example, if your constraints are just numbers, you can use {\ifnum\c>2} to only allow numbers that are greater than 2 (in general, your heads have to each expand to or behave equivalently to either \iftrue or \iffalse).
Within the guard you can access all matched constraints using \c as a list (i.e., access them with \c{0}, \c{1}, ...) based on the order of your heads (additionally, you can name them using \def\n{\c0}, ...).
Similarly, in your body, you can access all matched constraints as \c{i} with i being their 0-based index.
All heads, the guard, and the body can have side effects, given that they still expand to a conditional/update the constraint list chr@constraint in the case of the body (for this, you can use \body and \ebody, see below).
Additionally, there are helper functions like
\trueand\falsefor constant true and false guards or heads\log{text...}to output information during the execution. You have to call\enablelogso that logging works.\body{constraints,...}and\ebody{constraints,...}(expands with\edef) can be used in thebodyargument of\Rule(and\rule) to add new constraints more easily (to the main listchr@constraints). They are best used at the tail of the body.\LimitCycles{number}can be used to halt the execution after a maximum ofnumbercycles (e.g. if your Rules have no guaranteed fixpoint).\makelist{list-name}{elements,...}to construct lists (using them as\name{index}to access elements, setter and modifications functions are currently not exposed and live under the\chr@...namespace), see thelist.tex.\listequal{list-name1}{list-name2}to compare lists element-wise, expands to\iftrue/\iffalserespectively\permute{list-name}{length}which creates all permutations of the given length from the list (using a modified version of heap's algorithm) - currently it does not do fingerprinting (to avoid a problem with otherwise equal constraints) and therefore can produce the same combinations multiple times if|list-name| < length. For each combination, this expands the\chr@@outputmacro, which has access to thelist-namewith the current permutation and a shortened\chr@list@colllist-presentation (which can be used to copy the list with\makelist{list-name}{\chr@list@coll}.\makeatletterand\makeatotherhelp you to access all internal macros (which use the\chr@namespace).- Corresponding to
\Rule,\Compose, and\Run, there are lowercase variants\rule,\compose, and\runwhich take the names of lists (created with\makelistinstead of the lists directly.
You want fibonacci? You can have fibonacci!
\chr{fib test}{%
\LimitCycles{25}
\Compose{
\Rule{main}%
{} % empty kept head
{{\true}} % removed head
{\true}
{% poor man's tuple
\tuple{\c{0}}%
\add{\fst}{\snd}%
% ebody expands its argument to replace
\ebody{\snd:\res}%
}
}
\Run{{0:1}}
}To work with tuples you need some helpers:
\def\tuplehelper#1:#2\@nil{\def\fst{#1}\def\snd{#2}}
\def\tuple#1{\edef\@tmp{#1}\expandafter\tuplehelper\@tmp\@nil}
\def\add#1#2{\chr@tempcount=#1\relax\advance\chr@tempcount by #2\relax\edef\res{\the\chr@tempcount}}See the example.tex for a full example or the playground.tex for more.
Please note, that integer arithmetic is limited by TeX.
Footnotes
-
For the time being,
composeis limited to once-per-program (I was too lazy to implement proper nesting). ↩