uncommon-utils

Enums

Two kinds of enums are provided: traditional integer enums (see define enum) and class-based enums (see define enum-class).

Integer-based Enums

define enum Defining Macro

Defines a set of named integer constants along with a way to lookup the name from the value and vise versa.

Macro Call:

define enum name ()
  [ clauses ]
end [ enum ]

Example:

define enum nato-alphabet ()
  $alpha; $bravo; $charlie;
end;

This is the simplest form of define enum and is roughly equivalent to the following Dylan code:

define constant $alpha :: <int> = 1;
define constant $bravo :: <int> = 2;
define constant $charlie :: <int> = 3;
define constant $nato-alphabet-values = vector($alpha, $bravo, $charlie);
define constant $nato-alphabet-names = vector("$alpha", "$bravo", "$charlie");
define function nato-alphabet-to-name ...implementation elided... end;
define function name-to-nato-alphabet ...implementation elided... end;

It is also possible to assign explicit values and names to all or some of the enum items. The following enum shows an example of all possible enum clause forms:

define enum color ()
  $red;              // defines $red   :: <int> = 1  with name "$red"
  $green = 20;       // defines $green :: <int> = 20 with name "$green"
  $blue      "Blue"; // defines $blue  :: <int> = 21 with name "Blue"
  $cyan = 30 "Cyan"; // defines $cyan  :: <int> = 30 with name "Cyan"
end;

Class-based Enums

Class-based enums provide a concise way to define a class and a set of constants bound to an instance of that class, useful for cases where there is a well-defined, small set of values in the type. For example: the items in a menu, North South East West, or planets in the Solar System.

define enum-class Defining Macro

Defines a set of named constants along with a sequence containing all the constant values.

Macro Call:

define enum-class name ()
  [ slots ]
  [ clauses ]
end [ enum-class ]

Example: define a <planet> class and a constant for each planet in the Solar System.

define enum-class <planet> (<object>)
  constant slot %name :: <string>, required-init-keyword: name:;
  constant slot %mass :: <float>,  required-init-keyword: mass:;
  $mercury (name: "Mercury", mass: 1.1);
  $venus   (name: "Venus",   mass: 3.3);
  $mars    (name: "Mars",    mass: 5.5);
  ...etc...
end;

This defines the constants $mercury :: <planet>, $venus :: <planet> etc. and $planet-instances :: <seq> which contains each of the constants in the order they occur in the source.

Note

The name of the class must start with < and end with > or it will not match the macro pattern.

Trie

An implementation of the Trie data structure. In Dylan terms, a <trie> is a stretchy mutable explicit key collection in which the key is a <seq> leading to the graph node that contains the associated value. Its canonical use case is to store a dictionary of words.

API Overview

<trie> is the class that implements the Trie data structure and its collection protocol methods. It is abstract; calling make on <trie> returns an instance of <object-trie>.

make(<trie>) => {instance of <object-trie>}

The concrete subclasses of <trie> are also (usually indirect) subclasses of <trie-node>. This means that the empty sequence (e.g., #(), #[], or "") are the key that matches the value stored in the root of the Trie.

let t = make(<trie>);
t[""] := 100;

A <trie> is a stretchy, mutable, explicit key collection supporting the usual collection operations such as element, element-setter, size, etc.

Although <trie> does support forward-iteration-protocol, the implementation is extremely inefficient, essentially converting the trie to a <table> and calling forward-iteration-protocol on that. Use traverse instead if performance (or iteration order) matters.

Several concrete subclasses are provided to support different kinds of key lookup. These classes are named based on the way individual elements of the key are compared.

  • <object-trie> is the default implementation, comparing the elements of the key using ==. Use this for <string> keys if you want a case-sensitive comparison, or for keys that are sequences of integers, for example.

  • <ichar-trie> assumes the keys are strings and compares the elements of the key case-insensitively.

  • <string-trie> is for keys that are sequences of strings, compared case-sensitively.

  • <istring-trie> is for keys that are sequences of strings, compared case-insensitively.

Trie Reference

<trie> Open Abstract Class

A Trie is a kind of <collection> with keys that are sequences. Each element of the key leads to the next node in the Trie and the last node in that path has a value associated with it.

Superclasses:

<mutable-explicit-key-collection>, <stretchy-collection>

Init-Keywords:
  • node-class – An instance of <class>. The default is <object-trie-node>. When creating a node while adding a new element to a Trie, this determines what kind of node to create.

Calling make(<trie>, ...) returns a direct instance of <object-trie>, which compares key elements with == and has nodes that are (by default) direct instances of <object-trie-node>.

<trie-node> Open Abstract Class
Superclasses:

<object>

Init-Keywords:

Each node in a <trie> must be an instance of <trie-node>. Nodes that have a value comprise the elements of a collection; nodes with no value are just part of an existing key’s node path.

<object-trie> Class
Superclasses:

<trie-node>, <trie>

<object-trie-node> Class
Superclasses:

<trie-node>

The class of Trie node that compares key elements with ==.

<ichar-trie> Class
Superclasses:

<ichar-trie-node>, <trie>

Init-Keywords:

The class of Trie that compares key elements as case-insensitive characters. In other words, keys for this collection are instances of <string>.

<ichar-trie-node> Class
Superclasses:

<trie-node>

The class of Trie node that compares key elements as case-insensitive characters. This is the default node class for <ichar-trie>.

<string-trie> Class
Superclasses:

<string-trie-node>, <trie>

Init-Keywords:
<string-trie-node> Class
Superclasses:

<trie-node>

Init-Keywords:
  • children – An instance of <string-table>.

<istring-trie> Class
Superclasses:

<istring-trie-node>, <trie>

Init-Keywords:
<istring-trie-node> Class
Superclasses:

<trie-node>

Init-Keywords:
<trie-element-error> Class
Superclasses:

<simple-error>

The class of error signaled by element(<trie>, <object>) and element-setter(<object>, <trie>, <object>).

traverse Sealed Generic function
Signature:

traverse (fn node #key keys?) => ()

Applies the function fn to each node under (and including) node that has an associated value.

Parameters:

Traverses the entire Trie rooted at node, executing fn(node, depth) for each node with a value. If keys? is true then executes fn(node, deptth, key) for each node with a value. The latter can be expensive because it requires creating a sequence for each path to a value node. A node is passed to fn rather than the node’s value so that extra data stored in node subclasses can be accessed.

API for subclasses

The following definitions are primarily exported for use by subclassers.

child-node Open Generic function
Signature:

child-node (node key) => (child)

Retrieve an immediate child of node matching the given key.

Parameters:
Values:
  • child – An instance of <trie-node?>.

Note that this is a local operation on node, and key is only one element in the key used to access a Trie element. For example, if the Trie key is “foo”, then the key passed to child-node is 'f' or 'o'.

It is only necessary to implement this method if key is not sufficient for looking up an element in the node’s children data structure (usually an instance of <table>). For example, there is a method for (<ichar-trie-node>, <char>) so that it can lowercase the <char> before lookup.

child-node-setter Open Generic function
Signature:

child-node-setter (new-value node key) => (new-value)

Parameters:
Values:
  • new-value – An instance of <object>.

See the notes for child-node, which also apply to this method.

find-node Sealed Generic function
Signature:

find-node (node key) => (node)

Finds the node under node with the given key. This is similar to element(trie, key) except that instead of returning the value associated with the node it returns the node itself.

Parameters:
Values:
  • node – An instance of <trie-node?>.

node-value Open Generic function
Signature:

node-value (node) => (value)

Retrieves the value associated with node. If node has no value, $unsupplied is returned. (#f is a valid node value.)

Parameters:
Values:

Miscellaneous

<uint> Constant

Equivalent to limited(<int>, min: 0).

<uint?> Constant

Equivalent to false-or(<uint>).

See also:

<uint>

uint? Function
Signature:

uint? (object) => (bool)

Parameters:
Values:
  • bool – An instance of <bool>.

copy-seq Constant

Equivalent to copy-sequence. Renamed to match the <seq> type.

<istring-table> Constant

Equivalent to <case-insensitive-string-table>.

<singleton-object> Open Abstract Class
Superclasses:

<object>

Subclass this and calling make on your class will always return the same object regardless of the initialization arguments.

ash<< Function
Signature:

ash<< (i count) => (_)

Parameters:
  • i – An instance of <int>.

  • count – An instance of <uint>.

Values:
  • _ – An instance of <int>.

Arithmetic shift left. ash<<(i, n) is equivalent to ash(i, n), but makes the direction of the shift clearer.

ash>> Function
Signature:

ash>> (i count) => (_)

Parameters:
  • i – An instance of <int>.

  • count – An instance of <uint>.

Values:
  • _ – An instance of <int>.

Arithmetic shift right. ash>>(i, n) is equivalent to ash(i, -n), but makes the direction of the shift clearer.

begin1 Macro

Like begin, but returns the value of the first body expression. Inspired by Common Lisp’s prog1 special form.

count Function
Signature:

count (collection predicate #key limit) => (count)

Parameters:
Values:
  • count – An instance of <int>.

Count the number of elements in collection that match predicate, up to limit items. limit is an efficiency hack: stop counting when limit is reached, the idea being that you might want to know if there’s more than one.

iff Function Macro
Discussion:

A more concise replacement for if when the test/true/false expressions are short. Functions that contain a lot of if/else conditionals can grow in size quickly and this macro just provides a way to avoid the extra lines required for “else” and “end”.

Examples:

iff(i < len, loop(i + 1))

iff(i < len,
    loop(i + 1),
    result)

inc! Function Macro

A more concise way to increment a place.

Macro Call:

inc!(place)
inc!!(place, by)

Parameters:
  • place – A Dylan variable name or, if a corresponding -setter exists, a function call.

  • by – An instance of <object>. Default value: 1.

Values:
  • new-value – An instance of <object>.

Examples:

let my-dog-has-fleas = 1;
inc!(my-dog-has-fleas, 10);  // my-dog-has-fleas is now 10

// instead of slot-getter(object) := slot-getter(object) + 1;
inc!(slot-getter(object));
dec! Function Macro

A more concise way to decrement a place.

Macro Call:

dec!(place)
dec!!(place, by)

Parameters:
  • place – A Dylan variable name or, if a corresponding -setter exists, a function call.

  • by – An instance of <object>. Default value: 1.

Values:
  • new-value – An instance of <object>.

Examples:

let my-dog-has-fleas = 0;
dec!(my-dog-has-fleas, 10);  // my-dog-has-fleas is now -10

// instead of slot-getter(object) := slot-getter(object) - 1;
dec!(slot-getter(object));
with-restart Macro
with-simple-restart Macro