Module adapton::macros [] [src]

Macros to make using the engine module's interface more ergonomic.

Nominal memoization: Toy Examples

Below, we memoize several function calls to sum with different names and arguments. In real applications, the memoized function typically performs more work than summing two machine words. :)

use adapton::macros::*;
use adapton::engine::*;

// create an empty DCG (demanded computation graph)
manage::init_dcg();

// a simple function (memoized below for illustration purposes;
// probably actually not worth it!)
fn sum(x:usize, y:usize) -> usize {
    x + y
}

// Optional: Traces what the engine does below (for diagnostics, testing, illustration)
reflect::dcg_reflect_begin();

let nm_a_0 : Name = name_of_str("a"); // name "a"
let nm_a_1 : Name = name_of_str("a"); // name "a" (another copy)
let nm_b_0 : Name = name_of_str("b"); // name "b"
let nm_b_1 : Name = name_of_str("b"); // name "b" (another copy)

// create a memo entry, named "a", that remembers that `sum(42,43) = 85`
let res1 : usize = memo!(nm_a_0 =>> sum, x:42, y:43);

// same name "a", same arguments (42, 43) => reuses the memo entry above for `res1`
let res2 : usize = memo!(nm_a_1 =>> sum, x:42, y:43);

// different name "b", same arguments (42, 43) => will *not* match `res1`; creates a new entry
let res3 : usize = memo!(nm_b_0 =>> sum, x:42, y:43);

// same name "b", different arguments; will *overwrite* entry named "b" with new args & result
let res4 : usize = memo!(nm_b_1 =>> sum, x:55, y:66);

// Optional: Assert what happened above, in terms of analytical counts
let traces = reflect::dcg_reflect_end();
let counts = reflect::trace::trace_count(&traces, None);

// Editor allocated two thunks ("a" and "b")
assert_eq!(counts.alloc_fresh.0, 2);

// Editor allocated one thunk without changing it ("a", with same args)
assert_eq!(counts.alloc_nochange.0, 1);

// Editor allocated one thunk by changing it ("b", different args)
assert_eq!(counts.alloc_change.0, 1);

// Archivist allocated nothing
assert_eq!(counts.alloc_fresh.1, 0);

Some notes about the code above:

  • Callsite argument names: The macro memo! relies on programmer-supplied variable names in its macro expansion of these call sites, shown as x and y in the uses above. These can be chosen arbitrarily: So long as these symbols are distinct from one another, they can be any symbols, and need not actually match the formal argument names.

  • Type arguments: If the function call expects type arguments, memo! accomodates these calls with alternative syntax.

  • Spurious arguments: If the function call expects some later arguments that do not implement Eq, but are functionally determined by earlier ones that do (including the supplied Name), memo! accomodates these calls with alternative syntax. We call these arguments "spurious", since the Adapton engine does not check their identity when performing change propagation. Common examples include function values (e.g., anonymous closures).

Structs

ProgPt

Program points: used by the Adapton engine to distinguish different memoized functions.

Rc

A single-threaded reference-counting pointer.

Functions

bump_name_counter

Convenience function: A global counter for creating unique names, e.g., in unit tests. Avoid using this outside of unit tests.