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:
- 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:
- Init-Keywords:
Each node in a
<trie>
must be an instance of<trie-node>
. Nodes that have avalue
comprise the elements of a collection; nodes with no value are just part of an existing key’s node path.
- <object-trie> Class¶
- Superclasses:
- <ichar-trie> Class¶
- Superclasses:
- Init-Keywords:
node-class – An instance of
<object>
. The default is<ichar-trie-node>
.
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:
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:
- Init-Keywords:
node-class – The
<string-trie-node>
class.
- <string-trie-node> Class¶
- Superclasses:
- Init-Keywords:
children – An instance of
<string-table>
.
- <istring-trie> Class¶
- Superclasses:
- Init-Keywords:
node-class – The
<istring-trie-node>
class.
- <istring-trie-node> Class¶
- Superclasses:
- Init-Keywords:
children – An instance of
<istring-table>
.
- <trie-element-error> Class¶
- Superclasses:
The class of error signaled by
element(<trie>, <object>)
andelement-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:
fn – An instance of
<func>
.node – An instance of
<trie-node>
.keys? (#key) – An instance of
<bool>
.
Traverses the entire Trie rooted at node, executing
fn(node, depth)
for each node with a value. Ifkeys?
is true then executesfn(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:
node – An instance of
<trie-node>
.key – An instance of
<object>
.
- 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:
new-value – An instance of
<object>
.node – An instance of
<trie-node>
.key – An instance of
<object>
.
- 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:
node – An instance of
<trie-node>
.key – An instance of
<seq>
.
- 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:
node – An instance of
<trie-node>
.
- Values:
value – An instance of
<object>
.
Miscellaneous¶
- <uint> Constant¶
Equivalent to
limited(<int>, min: 0)
.
- <uint?> Constant¶
Equivalent to
false-or(<uint>)
.- See also:
<uint>
- uint? Function¶
- 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:
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:
- Values:
_ – An instance of
<int>
.
Arithmetic shift left.
ash<<(i, n)
is equivalent toash(i, n)
, but makes the direction of the shift clearer.
- ash>> Function¶
- Signature:
ash>> (i count) => (_)
- Parameters:
- Values:
_ – An instance of
<int>
.
Arithmetic shift right.
ash>>(i, n)
is equivalent toash(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’sprog1
special form.
- count Function¶
- Signature:
count (collection predicate #key limit) => (count)
- Parameters:
collection – An instance of
<collection>
.predicate – An instance of
<func>
.limit (#key) – An instance of
<object>
.
- 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¶