# `fractran_macros`
[![Build Status](https://travis-ci.org/huonw/fractran_macros.png)](https://travis-ci.org/huonw/fractran_macros)
A Rust macro for compiling
[FRACTRAN](https://en.wikipedia.org/wiki/FRACTRAN) programs embedded
in a Rust program into efficient, allocation-less,
libcore-only1 code at compile time.
FRACTRAN is a very simple language; a program is an integer `n` along
with a list of positive fractions, executed by finding the first
fraction `f` for which `nf` is an integer, replace `n` by `nf` and
repeating (execution halts when there is no such fraction). It turns
out that this is Turing complete, and people have even written
FRACTRAN interpreters in FRACTRAN! (See `examples/fractran.rs`.)
1That's right; you can now use FRACTRAN inside a kernel.
## Usage
The `fractran` macro takes a series of comma-separated arithmetic
expressions, representing the sequence of fractions. Supported
operations:
- `*`, `/` and parentheses for grouping; no risk of arithmetic
overflow or loss of precision,
- `+`; can overflow,
- integer powers via `^`; no overflow, but precedence is incorrect, so
`a^b * c` is `a^(b * c)`, rather than `(a^b) * c` as it should
be. Use parentheses to ensure correctness.
The macro returns a constructor function `fn(&[u32]) -> T`, where
`&[u32]` is the initial number (in the format
[described below](#representation)), and `T` is a type implementing
`Iterator<()>` and `fractran_support::Fractran`. Calling `next` will
step the machine (i.e. finding the appropriate fraction as described
above), returning `None` when the machine has halted.
The `fractran_support::Fractran` trait provides the `state` method
(for viewing the current number, in exponent form) and the `run`
method for executing the state machine until it halts.
### Example
```rust
#![feature(phase)]
#[phase(plugin)] extern crate fractran_macros;
fn main() {
// takes 2^a 3^b to 3^(a+b)
let add = fractran!(3/2);
println!("{}", add(&[12, 34]).run()); // [0, 46]
// takes 2^a 3^b to 5^(ab)
let mult = fractran!(455 / 33, 11/13, 1/11, 3/7, 11/2, 1/3);
println!("{}", mult(&[12, 34]).run()); // [0, 0, 408, 0, ...]
}
```
Remember to ensure the `Cargo.toml` has the appropriate dependencies:
```toml
[dependencies.fractran_macros]
git = "https://github.com/huonw/fractran_macros"
```
## Representation
Numbers are represented in terms of the (32-bit) exponents of their
prime factors. The `i`th entry of `[u32]` values is the exponent of
the `i`th prime (zero-indexed), for example `2 == [1]`, `3 == [0, 1]`,
`9438 == 2 * 3 * 11^2 * 13 == [1, 1, 0, 0, 2, 1]`. This representation
allows the implementation to handle very large numbers, anything where
the largest exponent of any prime is less than 232, so the
*smallest* non-representable number is 2232 =
24294967296.
This also allows the internal implementation to be highly efficient
with just (statically determined) array indexing and integer
comparisons & additions; there is no possibility of out-of-bounds
indexing (and thus no performance penalty from unwinding), nor is
there any division or remainder operations. As an example, the
`example/prime.rs` program uses Conway's prime enumeration FRACTRAN
program to generate primes, it takes only 6 seconds to do 1 billion
steps (reaching the lofty heights of 887).
Converting this representation to and from an actual number can be
achieved with your favourite prime-number crate (e.g. zipping with the
primes iterator from
[`slow_primes`](https://github.com/huonw/slow_primes)).
## Why?
Why not? [Esolang-macros](https://github.com/huonw/brainfuck_macros)
are fun, and so is the fundamental theorem of arithmetic.