Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/huonw/fractran_macros

A FRACTRAN procedural macro for Rust
https://github.com/huonw/fractran_macros

Last synced: about 1 month ago
JSON representation

A FRACTRAN procedural macro for Rust

Awesome Lists containing this project

README

        

# `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.