From 7f9f8b0729bcbe8da67957d56ea2dace7fd12bad Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 4 Aug 2019 00:37:55 +0100 Subject: [PATCH] doc/misc.tex: Document some more miscellaneous utilities. --- doc/misc.tex | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/doc/misc.tex b/doc/misc.tex index e286612..b1ade39 100644 --- a/doc/misc.tex +++ b/doc/misc.tex @@ -725,31 +725,138 @@ The following definitions are useful when working with conditions. \begin{describe}{fun} {frob-identifier @ \&key :swap-case :swap-hyphen @> @} + Return a `frobbed' version of the identifier @. Two different + transformations can be applied. + + \begin{itemize} + + \item If @ is non-nil (the default), and the letters in + @ are either all uppercase or all lowercase, then switch the case + of all of the letters. + + \item If @ is non-nil (the default), and @ contains + either hyphens @`--' or underscores @`_', but not both, then replace the + hyphens by underscores or \emph{vice-versa}. + + \end{itemize} + + (These are the `obvious' transformations to convert a C identifier into a + Lisp symbol.) + + Some examples: + \begin{itemize} + \item @|(frob-identifier "foo")| $\Longrightarrow$ @|"FOO"| + \item @|(frob-identifier "FOO")| $\Longrightarrow$ @|"foo"| + \item @|(frob-identifier "FooBar")| $\Longrightarrow$ @|"FooBar"| + \item @|(frob-identifier "Foo-Bar")| $\Longrightarrow$ @|"Foo_Bar"| + \item @|(frob-identifier "Foo_Bar")| $\Longrightarrow$ @|"Foo-Bar"| + \item @|(frob-identifier "foo_bar")| $\Longrightarrow$ @|"FOO-BAR"| + \item @|(frob-identifier "foo_bar" :swap-hyphen nil)| $\Longrightarrow$ + @|"FOO_BAR"| + \item @|(frob-identifier "foo_bar" :swap-case nil)| $\Longrightarrow$ + @|"foo-bar"| + \item @|(frob-identifier "foo_bar" :swap-case nil :swap-hyphen nil)| + $\Longrightarrow$ @|"foo_bar"| + \end{itemize} \end{describe} \begin{describe}{fun} - {compose @ \&rest @ @> @} + {compose @ @> @} + Return the left-to-right composition zero or more @. + + Let $f_1$, $f_2$, \ldots, $f_n$ be functions, and let $g = @|(compose $f_1$ + $f_2$ $\cdots$ $f_n$)|$ is their composition. If $g$ is applied to + arguments, the effect is as follows: first, $f_1$ is applied to the + arguments, yielding some value; $f_2$ is applied to this value, yielding a + second value; and so on, until finally the value yielded by $f_n$ is + returned as the result of $g$. Note that this is the reverse of the usual + mathematician's convention, but the author finds this ordering + significantly easier to work with: + \[ g = f_n \circ \cdots \circ f_2 \circ f_1 \] + + If any of the input functions return multiple values then \emph{all} of the + values are passed on to the next function in the list. (If the last + function returns multiple values then all of the values are returned from + the composition. + + The result of composing no functions is a function which simply returns all + of its arguments as values; essentially, $@|(compose)| \equiv + @|\#'values|$. \end{describe} \begin{describe}{mac}{defvar-unbound @ @ @> @} + Define a variable called @, with a @ string. + + The Common Lisp @|defvar| macro accepts both an initial value and a + doc-string as optional arguments, in that order, with the result that it's + not possible to define a variable and establish a documentation string for + it without also giving it an initial value. The @|defvar-unbound| macro, + on the other hand, never changes the symbol's variable-value. \end{describe} \begin{describe}{mac} {dosequence (@ @ @[[ :start @ @! :end @ @! - :indexvar @ @]]) \\ \ind + :indexvar @ @]]) \\ \ind @^* \\ @{ @ @! @ @}^*} + Iterate over a @. Common Lisp has a rich collection of iteration + primitives, and a rich collection of functions for working with sequences, + but no macro for iterating over the items of a sequence. + + First, the @ is evaluated. If @ and/or @ are + provided, they are also evaluated (in that order), which should produce + integers; @ may be also be nil. If not provided, or nil (in the case + of @), @ and @ default respectively to zero and the length + of the @. For each item in the sequence between the @ and + @ positions (i.e., each item in @|(subseq @ @ + @)|, in order, the body is evaluated as an implicit @|tagbody|, with + @ bound to the item and, if provided, @ bound to the item's + index. It is not specified whether the @ and @ are + let-bound or mutated in each iteration. + + Unlike other Common Lisp @|do|\dots\ forms, there is no `result' form. \end{describe} \begin{describe}{mac} {define-access-wrapper @ @ @[[ :read-only @ @]]} + Define @ as a function of one argument, so that @|(@ @)| + is equivalent to @|(@ @)|. If @ is nil (the + default), then also define @|(setf @)| so that @|(setf (@ + @) @)| is equivalent to @|(setf (@ @) @)|. + + In a @|defstruct| form, the accessor function names are constructed based + on the structure name and slot names. The structure name and accessor + names are part of the exported interface, but the slot names ideally + shouldn't be. This causes a problem when the slot name which will lead to + the right accessor is already an external symbol in some package. You can + solve this problem by choosing an internal name for the symbol, and then + using this macro to define an accessor function with the name that you + want, in terms of the accessor that @|defstruct| made. \end{describe} \begin{describe}{fun} {distinguished-point-shortest-paths @ @ @> @} + Calculate the shortest path from the @ to each node reachable from it + in a directed graph. The nodes of the graph can be any kind of object; + they will be compared using @|eql|. + + The @ should be a function which, given a node~$v$ as its + only argument, returns a list of cons cells @|($v'$ . $c'$)|, one for each + node~$v'$ adjacent to $v$, indicating the cost $c'$ of traversing the arc + from $v$ to $v'$. + + The return value is a list of cons cells @|($c$ . $p$)|, where $p$ is list + of nodes, in reverse order, along a path from the @ to some other + node, and $c$ is the total cost of traversing this path. (Therefore @|(car + $p$)| is the destination node, and @|(car (last $p$))| is always the + @ itself.) + + The function runs in $O(n^2)$ time, where $n$ is the number of nodes + reachable from the @. Currently, it uses an algorithm due to Edsger + Dijkstra. \end{describe} %%%-------------------------------------------------------------------------- -- 2.11.0