% This LaTeX document was generated using the LaTeX backend of PlDoc,
% The SWI-Prolog documentation system

\chapter{Canny bag o' Tudor}

!\href{https://shields.io/endpoint?url=https://gist.githubusercontent.com/royratcliffe/ec92ac84832950815861d35c2f661953/raw/cov.json}{cov}
!\href{https://shields.io/endpoint?url=https://gist.githubusercontent.com/royratcliffe/ec92ac84832950815861d35c2f661953/raw/fail.json}{fail}

See \href{https://github.com/royratcliffe/canny_tudor/blob/main/man/canny_tudor.pdf}{PDF} for details.

This is an experimental SWI-Prolog 'pack' comprising technical spikes, or
otherwise useful, Prolog predicates that do not seem to fit anywhere else.

The package name reflects a mixed bag of bits and pieces. It's a phrase from the
North-East corner of England, United Kingdom. 'Canny' means nice, or good. Tudor
is a crisp (chip, in American) manufacturer. This pack comprises various
unrelated predicates that may, or may not, be tasty; like crisps in a bag, the
library sub-folders and module names delineate the disparate components. If the
sub-modules grow to warrant a larger division, they can ultimately fork their
own pack.

The pack comprises experimental modules subject to change and revision
due to its nature. The pack's major version will always remain 0.
Work in progress!\chapter{library(canny/a)}\label{sec:a}

\begin{description}
    \predicate[det]{a_star}{3}{+Heuristics0, -Heuristics, +Options}
Offers a static non-Constraint Handling Rules interface to \predref{a_star}{4}.
Performs a simplified A* search using CHR where the input is a list
of \textit{all the possible} arcs along with their cost. Each element in
\arg{Heuristics0} is a \predref{h}{3} term specifying source of the heuristic arc,
the arc's destination node and the cost of traversing in-between.
Nodes specify distinct but arbitrary terms. Only terms \const{initial} and
\const{final} have semantic significance. You can override these using
\arg{Options} for \const{initially} and \const{finally}. For \arg{Options} see below.

Simplifies the CHR implementation by accepting \predref{h}{3} terms as a list
rather than using predicates to expand nodes. We match heuristic
terms using \predref{member}{2} from the list of heuristics. This interface does
\textbf{not} replace \predref{a_star}{4} since having a pre-loaded list of
heuristics is not always possible or feasible, for example when the
number of arcs is very large such as when traversing a grid of arcs.

Here is a simple example.

\begin{code}
?- a_star([h(a, b, 1)], A, [initially(a), finally(b)]).
A = [h(a, b, 1)].
\end{code}

\arg{Options} include:

\begin{itemize}
    \item \verb$initially(Initial)$ defines the initial node, defaults to
atom \const{initial}.
    \item \verb$finally(Final)$ defines the final node, atom \const{final} by default.
    \item \verb$reverse(Boolean)$ reverses the outgoing selected \arg{Heuristics} so that
the order reflects the forward order of traverse. The underlying
expansion pushes path nodes to the head of the list resulting in a
final-to-initial traversal by default.
\end{itemize}

\begin{tags}
    \tag{See also}
\url{https://rosettacode.org/wiki/A*_search_algorithm}
\end{tags}
\end{description}

\chapter{library(canny/arch)}\label{sec:arch}

\begin{description}
    \predicate[semidet]{current_arch}{1}{?Arch:pair}
Unifies \arg{Arch} with the current host's architecture and operating
system. Usefully reads the pair as a Prolog term with which you can
unify its component parts.

The Prolog \const{arch} flag combines both the architecture and the
operating system as a dash-separated pair. The predicate splits
these two components apart by reading the underlying atom as a
Prolog term. This makes an assumption about the format of the \const{arch}
flag.

    \predicate[semidet]{current_arch_os}{2}{?Arch, ?OS}
Unifies \arg{OS} with the current operating system. Splits the host
architecture into its two components: the bit-wise sub-architecture
and the operating system. Operating system is one of: \const{win32} or
\const{win64} for Windows, \const{darwin} for macOS, or \const{linux} for Linux. Maps
architecture bit-width to an atomic \arg{Arch} token for contemporary
64-bit hosts, one of: \const{x64}, \verb$x86_64$. Darwin and Linux report the
latter, Windows the former.

    \predicate[semidet]{current_os}{1}{?OS}
Succeeds for current \arg{OS}, one of:

\begin{shortlist}
    \item \const{win32}
    \item \const{win64}
    \item \const{darwin}
    \item \const{linux}
\end{shortlist}
\end{description}

\chapter{library(canny/arity)}\label{sec:arity}

\begin{description}
    \predicate[semidet]{arities}{2}{?Arities0:compound, ?Arities:list}
Suppose that you want to accept arity arguments of the form \{A, ...\}
where A is the first integer element of a comma-separated list of
arity numbers. The \arg{Arities0} form is a compound term enclosed within
braces, comprising integers delimited by commas. The \predref{arities}{2}
predicate extracts the arities as a list.

Empty lists fail. Also, lists containing non-integers fail to unify.
The implementation works forwards and backwards: arity compound to
arity list or vice versa, mode (+, -) or mode (-, +).
\end{description}

\chapter{library(canny/bits)}\label{sec:bits}

\begin{description}
    \predicate[semidet]{bits}{5}{+Shift, +Width, ?Word, ?Bits, ?Rest}
\nodescription
    \predicate[semidet]{bits}{4}{+ShiftWidthPair, ?Word, ?Bits, ?Rest}
\nodescription
    \predicate[semidet]{bits}{3}{+ShiftWidthPair, ?Word, ?Bits}
Unifies \arg{Bits} within a \arg{Word} using \arg{Shift} and \arg{Width}. All arguments are
integers treated as words of arbitrary bit-width.

The implementation uses relational integer arithmetic, i.e. CLP(FD).
Hence allows for forward and backward transformations from \arg{Word} to
\arg{Bits} and vice versa. Integer \arg{Word} applies a \arg{Shift} and bit \arg{Width} mask
to integer \arg{Bits}. \arg{Bits} is always a smaller integer. Decomposes the
problem into shifting and masking. Treats these operations
separately.

\begin{arguments}
\arg{Width} & of \arg{Bits} from \arg{Word} after \arg{Shift}. \arg{Width} of zero always
fails. \\
\end{arguments}

    \predicate[semidet]{bit_fields}{3}{+Fields:list, +Shift:integer, +Int:integer}
\nodescription
    \predicate[semidet]{bit_fields}{4}{+Fields:list, +Shift:integer, +Int0:integer, -Int:integer}
Two versions of the predicate unify \arg{Value}:\arg{Width} bit fields with
integers. The arity-3 version requires a bound \arg{Int} from which to
find unbound (or bound) values in the \arg{Fields}; used to extract values
from integers else check values semi-deterministically. The arity-4
version of the predicate accumulates bit-field values by OR-wise
merging shifted bits from \arg{Int0} to \arg{Int}.

The predicates are semi-deterministic. They can fail. Failure occurs
when the bit-field \arg{Width} integers do \textbf{not} sum to \arg{Shift}.

\begin{arguments}
\arg{Fields} & is a list of value and width terms of the form
\verb$Value:Width$ where \arg{Width} is an integer; \arg{Value} is either a
variable or an integer. \\
\arg{Shift} & is an integer number of total bits, e.g. 8 for eight-bit
bytes, 16 for sixteen-bit words and so on. \\
\end{arguments}

    \predicate[semidet]{rbit}{3}{+Shift:integer, +Int:integer, ?Reverse:integer}
Bit reversal over a given span of bits. The reverse bits equal the
mirror image of the original; integer \$1\$ reversed in 16 bits
becomes \$8000_\{16\}\$ for instance.

Arity-3 \predref{rbit}{3} predicate throws away the residual. Any bit values
lying outside the shifting span disappear; they do not appear in the
residual and the predicate discards them. The order of the sub-terms
is not very important, except for failures. Placing \const{succ} first
ensures that recursive shifting fails if \arg{Shift} is not a positive
integer; it triggers an exception if not actually an integer.
\end{description}

\chapter{library(canny/cover)}\label{sec:cover}

\begin{description}
    \predicate[det]{coverages_by_module}{2}{:Goal, -Coverages:dict}
Calls \arg{Goal} within \predref{show_coverage}{1} while capturing the resulting
lines of output; \arg{Goal} is typically \predref{run_tests}{0} for running all
loaded tests. Parses the lines for coverage statistics by module.
Ignores lines that do not represent coverage, and also ignores lines
that cover non-module files. Automatically matches prefix-truncated
coverage paths as well as full paths.

\begin{arguments}
\arg{Coverages} & is a module-keyed dictionary of sub-dictionaries
carrying three keys: clauses, cov and fail. \\
\end{arguments}

    \predicate[nondet]{coverage_for_modules}{4}{:Goal, +Modules, -Module, -Coverage}
Non-deterministically finds \arg{Coverage} dictionaries for all \arg{Modules}.
Bypasses those modules excluded from the required list, typically
the list of modules belonging to a particular pack and excluding all
system and other supporting modules.
\end{description}

\chapter{library(canny/crc)}\label{sec:crc}

\begin{description}
    \predicate[semidet]{crc}{2}{+Predefined, -CRC}
Builds a predefined \arg{CRC} accumulator.

\begin{arguments}
\arg{Predefined} & specifies a predefined \arg{CRC} computation. \\
\arg{CRC} & a newly-initialised \arg{CRC} term with the correct polynomial,
initial value and any necessary options such as bit reversal and
inversion value. \\
\end{arguments}

    \predicate[semidet]{crc_property}{2}{+CRC, ?Property}
Extracts the \arg{CRC}'s checksum for comparison, or unifies with other
interesting values belonging to a \arg{CRC} accumulator.

    \predicate[semidet]{crc}{3}{+CRC0, +Term, -CRC}
Mutates \arg{CRC0} to \arg{CRC} by feeding in a byte code, or a list of
byte codes.

\begin{arguments}
\arg{CRC0} & the initial or thus-far accumulated \arg{CRC}. \\
\arg{Term} & a byte code or a list of byte codes. \\
\arg{CRC} & the updated \arg{CRC}. \\
\end{arguments}

    \predicate[det]{crc_16_mcrf4xx}{1}{-Check}
Initialises CRC-16/MCRF4XX checksum.

    \predicate[det]{crc_16_mcrf4xx}{3}{+Check0, +Data, -Check}
Accumulates CRC-16/MCRF4XX checksum using optimal shifting and
exclusive-OR operations.
\end{description}

\chapter{library(canny/docker): Canny Docker}\label{sec:docker}

\begin{tags}
    \tag{author}
Roy Ratcliffe
    \tag{version}
0.1.0
\end{tags}

This module provides an interface to the Docker API, allowing interaction with
Docker services through HTTP requests. It defines settings for the Docker daemon
URL and API version, and provides a predicate to construct URLs and options for
various Docker operations.

It supports operations such as listing containers, creating containers, and
checking the Docker system status. The module uses Prolog dictionaries to
represent JSON data structures, making it easy to work with the Docker API's
responses. It also includes utility predicates for transforming dictionary
key-value pairs and constructing paths for API requests. It is designed to be
used in conjunction with the HTTP client library to make requests to the Docker
API. It provides a flexible way to interact with Docker services, allowing for
dynamic construction of API requests based on the specified operations and
options.

\section{Docker API Operations}

The module supports various Docker API operations, such as:

\begin{shortlist}
    \item \verb$system_ping$: Check if the Docker daemon is reachable.
    \item \verb$container_list$: List all containers.
    \item \verb$container_create$: Create a new container.
    \item \verb$network_create$: Create a new network.
    \item \verb$network_delete$: Delete a network.
\end{shortlist}

These operations are defined in the Docker API specification and can be accessed
through the \predref{docker}{3} predicate, which constructs the appropriate URL and
options based on the operation and the settings defined in this module.

\subsection{Example container operations}

The following examples demonstrate how to list and create Docker containers
using the \predref{docker}{3} predicate. The first example lists all containers, and the
second example creates a new container with a specified image and labels.

\begin{code}
?- docker(container_list, Reply).
Reply = [json(['Id'='abc123', 'Image'='ubuntu:latest', ...|...])].
?- docker(container_create, Reply, [post(json(json(['Image'=ubuntu,
   'Labels'=json(['Hello'=world)])))])).
Reply = _{Id:"abc123", Warnings:[]}.
\end{code}

The \predref{container_list}{2} predicate retrieves a list of all containers, returning
a list of dictionaries representing each container. Each dictionary contains
information such as the container ID, image, and other metadata.
The \predref{container_create}{3} predicate creates a new container with the specified
image and labels. The labels are specified as a JSON object, allowing for
flexible tagging of containers with metadata. The reply contains the ID of the
created container and any warnings that may have occurred during the creation
process. The labels can be used to organise and manage containers based on
specific criteria, such as purpose or owner.

\subsection{Example network operations}

The following examples demonstrate how to create and delete a Docker network
using the \predref{docker}{3} predicate. The network is created with a name and labels,
and then deleted by its name.

\begin{code}
?- docker(network_create(_{name:my_network, labels:_{'my.label':'my-value'}}), A).
A = _{id:"1be0f5d2337ff6a6db79a59707049c199268591f49e3c9054fc698fe7916f9c3", warning:""}.

38 ?- docker(network_delete(my_network), A).
A = ''.
\end{code}

Note that the \predref{network_create}{2} predicate constructs a network with the
specified name and labels, and returns a reply containing the network ID and any
warnings. The \predref{network_delete}{2} predicate deletes the network by its name,
returning an empty reply if successful.

Labels can be used to tag networks with metadata, which can be useful
for organising and managing Docker resources. The labels are specified
as a dictionary with key-value pairs, where the keys and values are
strings. The labels are included in the network configuration when
creating a network, allowing for flexible and dynamic tagging of Docker
resources.

Labels can be used to filter and query networks, making it easier to
manage Docker resources based on specific criteria. For example, you can
create a network with a label indicating its purpose or owner, and then
use that label to find networks that match certain criteria. This allows
for more organised and efficient management of Docker resources,
especially in larger deployments with many networks and containers.

\subsection{Restyling Keys}

The \predref{docker}{3} predicate transforms the keys in the input dictionary to
CamelCase format using the \predref{restyle_key}{3} predicate, which applies the
Docker-specific CamelCase naming convention to the keys. This
transformation is useful for ensuring that the keys in the input
dictionary match the expected format for the Docker API, making it
easier to work with the API and ensuring compatibility with the expected
request format.

The transformation is applied recursively to all
key-value pairs in the input dictionary, ensuring that all keys are
transformed to the correct format before making the request to the
Docker API. The reverse transformation is applied to the reply
dictionary, which does not retain the original key names as returned by
the Docker API. Label keys are also transformed to CamelCase format,
ensuring consistency in the naming convention used for labels in the
Docker API requests and responses.

\section{Low-Level HTTP Requests}

The module provides a low-level interface to the Docker API, allowing for custom
HTTP requests to be made. The \predref{docker}{3} predicate constructs the URL and
options for the specified operation, and uses the \predref{http_get}{3} predicate to make
the request. The options can include HTTP methods, headers, and other parameters
as needed for the specific operation.

The \predref{url_options}{4} predicate is used to construct the URL and options for a
specific Docker operation. It retrieves the operation details from the Docker
API specification and formats the path according to the specified version and
operation. The resulting URL and options can be used with the HTTP client to
make requests to the Docker API.

\subsection{Example usage}

The \predref{url_options}{4} predicate can be used to construct the URL and options for a
specific Docker operation. For example, to get the URL and options for the
\verb$system_ping$ operation, you can use:

\begin{code}
?- [library(http/http_client)].
true.

?- canny_docker:url_options(system_ping, URL, Options),
   http_get(URL, Reply, Options).
URL = [path('/v1.49/_ping'), protocol(tcp), host(localhost), port(2375)],
Options = [method(get), accept(["text/plain"])],
Reply = 'OK'.
\end{code}

For listing containers, you can use:

\begin{code}
?- canny_docker:url_options(container_list, URL, Options),
   http_get(URL, Reply, Options).
URL = [path('/v1.49/containers/json'), protocol(tcp), host(localhost), port(2375)],
Options = [method(get), accept(["application/json"])],
Reply = [json(['Id'=..., ...|...])].
\end{code}

For creating a container, you can use:

\begin{code}
?- docker(container_create, A, [post(json(json(['Image'=ubuntu,
   'Labels'=json(['Hello'=world])])))]).
\end{code}

This example creates a new Docker container with the specified image and labels.
Notice that the post request uses \verb$json(json(...))$ to specify the JSON body of
the request.\vspace{0.7cm}

\begin{description}
    \predicate[det]{docker}{2}{+Ask, -Reply}
Issues a request to the Docker API using the specified \arg{Ask} term and
returns the \arg{Reply}. The \arg{Ask} term may be a compound specifying the
operation to perform together with any required arguments.

The Docker API request comprises:

\begin{itemize}
    \item a path with zero or more placeholders,
    \item a method,
    \item zero or more required or optional search parameters,
    \item a JSON body for POST requests.
\end{itemize}

This implies that, for the least amount of additional information, a
request is just a path with a method, e.g., a GET, HEAD or DELETE
request. From that point onward, requests grow in complexity
involving or more of the following: path placeholders, query
parameters, a request body.

The complexity of the request can vary significantly based on the
operation being performed and the specific requirements of the
Docker API. The \predref{docker}{2} predicate is designed to handle these
variations and provide a consistent interface for interacting with
the Docker API. It abstracts away the details of constructing the
request and processing the response, allowing users to focus on
the high-level operation they want to perform. Path placeholders
appear in the first \arg{Ask} term argument as atomic values. URL query parameters
are specified as a list of key-value pairs in the \arg{Ask} term argument.
POST request payloads are specified as a Prolog dictionary as the \arg{Ask} term.

The \arg{Ask} term is a compound term that specifies the operation to
perform, such as \verb$container_list$ or \verb$system_ping$. The \arg{Reply} is a
Prolog term that represents the response from the Docker API, which
is typically a Prolog dictionary or list, depending on the operation.

The predicate constructs the URL and options based on the operation
and the settings defined in this module. It uses the \predref{ask}{4} predicate
to determine the path, method, and any additional options required for
the request. The URL is constructed by appending the path to the
\verb$daemon_url$ setting, and the HTTP request is made using the
\predref{http_get}{3} predicate from the HTTP client library.

The \arg{Reply} is then processed to ensure that the keys in the response
are transformed to CamelCase format using the \predref{restyle_value}{3}
predicate. This transformation is useful for ensuring that the keys
in the response match the expected format for the Docker API, making
it easier to work with the API and ensuring compatibility with the
expected response format.

\begin{arguments}
\arg{Ask} & The \arg{Ask} term specifies the operation to perform, which may
include path placeholders, query parameters, and a request body. The \arg{Ask}
term is a compound term that identifies the operation and provides any
necessary arguments or parameters for the request. The \arg{Ask} term can be a
simple atom for operations with no arguments, or it can be a more complex
term that includes arguments. The \arg{Ask} term is used to construct the URL and
options for the request, allowing for flexible and dynamic construction of
API requests based on the specified
operation and options. \\
\arg{Reply} & The \arg{Reply} is the response from the Docker API, which is
typically a Prolog dictionary or list, depending on the operation. It can
also be an atom. The \arg{Reply} is a Prolog term that represents the data
returned by the Docker API after processing the request. It contains the
results of the operation, such as a list of containers, the status of a
container, or the result of a command. \\
\end{arguments}

    \predicate[det]{docker}{3}{+Operation, -Reply, +Options}
Makes a request to the Docker API using the specified operation and
options. The operation is a string that identifies the Docker API
operation to perform, such as \verb$container_list$ or \verb$system_ping$. The
predicate constructs the URL and options based on the operation and
the settings defined in this module.

Builds HTTP request options for the Docker API using the base URL from
the \verb$daemon_url$ setting. The path and HTTP method are determined by
\predref{path_and_method}{4}, and the resulting options are suitable for making
requests to the Docker API.

The predicate constructs the URL by concatenating the base URL with
the path and method. The \verb$daemon_url$ setting provides the base URL,
and the \verb$api_version$ setting specifies the version of the Docker API.

\begin{arguments}
\arg{Operation} & The operation to perform, which determines the path and
method, as well as any additional options. \\
\arg{Reply} & The response from the Docker API, which is typically a
Prolog dictionary or list, depending on the operation. \\
\arg{Options} & This is a list of options that control both how the path is
formatted and how the HTTP request is made. For path formatting, options are
terms like \verb$id(Value)$ that provide values for placeholders in the path
template. For the HTTP request, options can include settings such as
headers, authentication, or other parameters supported by the HTTP client. \\
\end{arguments}

    \predicate[semidet]{docker_path_options}{3}{?Operation, -Path, -Options}
Constructs the \arg{Path} and \arg{Options} for a Docker API operation. The predicate
retrieves the operation details from the Docker API specification and
formats the path according to the default version and operation. The
resulting path and options can be used with the HTTP client to make requests
to the Docker API.

The predicate uses the \predref{docker_path_options}{4} predicate to construct the
path and options for the specified operation. It retrieves the operation
details from the Docker API specification and formats the path according to
the specified version and operation. The resulting path and options can be
used with the HTTP client to make requests to the Docker API.

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
build_prune & '/v1.49/build/prune' & post \\
config_create & '/v1.49/configs/create' & post \\
config_delete & '/v1.49/configs/\{id\}' & delete \\
config_inspect & '/v1.49/configs/\{id\}' & get \\
config_list & '/v1.49/configs' & get \\
config_update & '/v1.49/configs/\{id\}/update' & post \\
\hline
\end{tabulary}
\end{quote}

For container operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
container_archive & '/v1.49/containers/\{id\}/archive' & get \\
container_archive_info & '/v1.49/containers/\{id\}/archive' & head \\
container_attach & '/v1.49/containers/\{id\}/attach' & post \\
container_attach_websocket & '/v1.49/containers/\{id\}/attach/ws' & get \\
container_changes & '/v1.49/containers/\{id\}/changes' & get \\
container_create & '/v1.49/containers/create' & post \\
container_delete & '/v1.49/containers/\{id\}' & delete \\
container_exec & '/v1.49/containers/\{id\}/exec' & post \\
container_export & '/v1.49/containers/\{id\}/export' & get \\
container_inspect & '/v1.49/containers/\{id\}/json' & get \\
container_kill & '/v1.49/containers/\{id\}/kill' & post \\
container_list & '/v1.49/containers/json' & get \\
container_logs & '/v1.49/containers/\{id\}/logs' & get \\
container_pause & '/v1.49/containers/\{id\}/pause' & post \\
container_prune & '/v1.49/containers/prune' & post \\
container_rename & '/v1.49/containers/\{id\}/rename' & post \\
container_resize & '/v1.49/containers/\{id\}/resize' & post \\
container_restart & '/v1.49/containers/\{id\}/restart' & post \\
container_start & '/v1.49/containers/\{id\}/start' & post \\
container_stats & '/v1.49/containers/\{id\}/stats' & get \\
container_stop & '/v1.49/containers/\{id\}/stop' & post \\
container_top & '/v1.49/containers/\{id\}/top' & get \\
container_unpause & '/v1.49/containers/\{id\}/unpause' & post \\
container_update & '/v1.49/containers/\{id\}/update' & post \\
container_wait & '/v1.49/containers/\{id\}/wait' & post \\
put_container_archive & '/v1.49/containers/\{id\}/archive' & put \\
\hline
\end{tabulary}
\end{quote}

For distribution operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
distribution_inspect & '/v1.49/distribution/\{name\}/json' & get \\
\hline
\end{tabulary}
\end{quote}

For exec operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
exec_inspect & '/v1.49/exec/\{id\}/json' & get \\
exec_resize & '/v1.49/exec/\{id\}/resize' & post \\
exec_start & '/v1.49/exec/\{id\}/start' & post \\
\hline
\end{tabulary}
\end{quote}

For image operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
image_build & '/v1.49/build' & post \\
image_commit & '/v1.49/commit' & post \\
image_create & '/v1.49/images/create' & post \\
image_delete & '/v1.49/images/\{name\}' & delete \\
image_get & '/v1.49/images/\{name\}/get' & get \\
image_get_all & '/v1.49/images/get' & get \\
image_history & '/v1.49/images/\{name\}/history' & get \\
image_inspect & '/v1.49/images/\{name\}/json' & get \\
image_list & '/v1.49/images/json' & get \\
image_load & '/v1.49/images/load' & post \\
image_prune & '/v1.49/images/prune' & post \\
image_push & '/v1.49/images/\{name\}/push' & post \\
image_search & '/v1.49/images/search' & get \\
image_tag & '/v1.49/images/\{name\}/tag' & post \\
\hline
\end{tabulary}
\end{quote}

For network operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
network_connect & '/v1.49/networks/\{id\}/connect' & post \\
network_create & '/v1.49/networks/create' & post \\
network_delete & '/v1.49/networks/\{id\}' & delete \\
network_disconnect & '/v1.49/networks/\{id\}/disconnect' & post \\
network_inspect & '/v1.49/networks/\{id\}' & get \\
network_list & '/v1.49/networks' & get \\
network_prune & '/v1.49/networks/prune' & post \\
\hline
\end{tabulary}
\end{quote}

For node operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
node_delete & '/v1.49/nodes/\{id\}' & delete \\
node_inspect & '/v1.49/nodes/\{id\}' & get \\
node_list & '/v1.49/nodes' & get \\
node_update & '/v1.49/nodes/\{id\}/update' & post \\
\hline
\end{tabulary}
\end{quote}

For plugin operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
plugin_create & '/v1.49/plugins/create' & post \\
plugin_delete & '/v1.49/plugins/\{name\}' & delete \\
plugin_disable & '/v1.49/plugins/\{name\}/disable' & post \\
plugin_enable & '/v1.49/plugins/\{name\}/enable' & post \\
plugin_inspect & '/v1.49/plugins/\{name\}/json' & get \\
plugin_list & '/v1.49/plugins' & get \\
plugin_pull & '/v1.49/plugins/pull' & post \\
plugin_push & '/v1.49/plugins/\{name\}/push' & post \\
plugin_set & '/v1.49/plugins/\{name\}/set' & post \\
plugin_upgrade & '/v1.49/plugins/\{name\}/upgrade' & post \\
get_plugin_privileges & '/v1.49/plugins/privileges' & get \\
\hline
\end{tabulary}
\end{quote}

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
secret_create & '/v1.49/secrets/create' & post \\
secret_delete & '/v1.49/secrets/\{id\}' & delete \\
secret_inspect & '/v1.49/secrets/\{id\}' & get \\
secret_list & '/v1.49/secrets' & get \\
secret_update & '/v1.49/secrets/\{id\}/update' & post \\
\hline
\end{tabulary}
\end{quote}

For service operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
service_create & '/v1.49/services/create' & post \\
service_delete & '/v1.49/services/\{id\}' & delete \\
service_inspect & '/v1.49/services/\{id\}' & get \\
service_list & '/v1.49/services' & get \\
service_logs & '/v1.49/services/\{id\}/logs' & get \\
service_update & '/v1.49/services/\{id\}/update' & post \\
\hline
\end{tabulary}
\end{quote}

For session operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
session & '/v1.49/session' & post \\
\hline
\end{tabulary}
\end{quote}

For swarm operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
swarm_init & '/v1.49/swarm/init' & post \\
swarm_inspect & '/v1.49/swarm' & get \\
swarm_join & '/v1.49/swarm/join' & post \\
swarm_leave & '/v1.49/swarm/leave' & post \\
swarm_unlock & '/v1.49/swarm/unlock' & post \\
swarm_unlockkey & '/v1.49/swarm/unlockkey' & get \\
swarm_update & '/v1.49/swarm/update' & post \\
\hline
\end{tabulary}
\end{quote}

For system operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
system_auth & '/v1.49/auth' & post \\
system_data_usage & '/v1.49/system/df' & get \\
system_events & '/v1.49/events' & get \\
system_info & '/v1.49/info' & get \\
system_ping & '/v1.49/_ping' & get \\
system_ping_head & '/v1.49/_ping' & head \\
system_version & '/v1.49/version' & get \\
\hline
\end{tabulary}
\end{quote}

For task operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
task_inspect & '/v1.49/tasks/\{id\}' & get \\
task_list & '/v1.49/tasks' & get \\
task_logs & '/v1.49/tasks/\{id\}/logs' & get \\
\hline
\end{tabulary}
\end{quote}

For volume operations, the following paths and options are defined:

\begin{quote}
\begin{tabulary}{0.9\textwidth}{|l|L|l|}
\hline
volume_create & '/v1.49/volumes/create' & post \\
volume_delete & '/v1.49/volumes/\{name\}' & delete \\
volume_inspect & '/v1.49/volumes/\{name\}' & get \\
volume_list & '/v1.49/volumes' & get \\
volume_prune & '/v1.49/volumes/prune' & post \\
volume_update & '/v1.49/volumes/\{name\}' & put \\
\hline
\end{tabulary}
\end{quote}

\begin{arguments}
\arg{Operation} & The operation to perform, which determines the path and
method, as well as any additional options. \\
\arg{Path} & The path for the operation, which is derived from the
Docker API specification. \\
\arg{Options} & List of options for the HTTP request, such as \const{method} and
\const{accept}. \\
\end{arguments}
\end{description}

\chapter{library(canny/endian): Big- and little-endian grammars}\label{sec:endian}

The endian predicates unify big- and little-endian words, longs and
long words with lists of octets by applying shifts and masks to
correctly align integer values with their endian-specific octet
positions. They utilise integer-relational finite domain CLP(FD)
predicates in order to implement forward and reverse translation
between octets and integers.

Use of CLP allows the DCG clauses to express the integer relations
between octets and their integer interpretations implicitly. The
constraints simultaneously define a byte in terms of an octet and
vice versa.\vspace{0.7cm}

\begin{description}
    \dcg[semidet]{byte}{1}{?Byte:integer}
Parses or generates an octet for \arg{Byte}. Bytes are eight bits wide and
unify with octets between 0 and 255 inclusive. Fails for octets
falling outside this valid range.

\begin{arguments}
\arg{Byte} & value of octet. \\
\end{arguments}

    \dcg[semidet]{big_endian}{2}{?Width:integer, ?Word:integer}
Unifies big-endian words with octets.

Example as follows: four octets to one big-endian 32-bit word.

\begin{code}
?- phrase(big_endian(32, A), [4, 3, 2, 1]),
   format('~16r~n', [A]).
4030201
\end{code}

    \dcg[semidet]{little_endian}{2}{?Width:integer, ?Word:integer}
Unifies little-endian words with octet stream.
\end{description}

\chapter{library(canny/exe)}\label{sec:exe}

\begin{description}
    \predicate[semidet]{exe}{3}{+Executable, +Arguments, +Options}
Implements an experimental approach to wrapping \predref{process_create}{3}
using \predref{concurrent}{3}. It operates concurrent pipe reads, pipe writes
and process waits. Predicate parameters match \predref{process_create}{3} but
with a few minor but key improvements. New \arg{Options} terms offer
additional enhanced pipe streaming arguments. See
partially-enumerated list below.

\begin{shortlist}
    \item \verb$stdin(codes(Codes))$
    \item \verb$stdin(atom(Atom))$
    \item \verb$stdin(string(String))$
    \item \verb$stdout(codes(Codes))$
    \item \verb$stdout(atom(Atom))$
    \item \verb$stdout(string(String))$
    \item \verb$stderr(codes(Codes))$
    \item \verb$stderr(atom(Atom))$
    \item \verb$stderr(string(String))$
    \item \verb$status(Status)$
\end{shortlist}

If \arg{Options} specifies any of the above terms, \predref{exe}{3} prepares goals to
write, read and wait concurrently as necessary according to the
required configuration. This implies that reading standard output
and waiting for the process status happens at the same time. Same
goes for writing to standard input. The number of concurrent threads
therefore exactly matches the number of concurrent process goals.
This goes for clean-up goals as well. Predicate \predref{concurrent}{3} does
not allow zero threads however; it throws a \verb$type_error$. The
implementation always assigns at least one thread which amounts to
reusing the calling thread non-concurrently.

All the \const{std} terms above can also take a stream options list, so
can override default encoding on the process pipes. The following
example illustrates. It sends a friendly "hello" in Mandarin Chinese
through the Unix \const{tee} command which relays the stream to standard
output and tees it off to \verb$/dev/stderr$ or standard error for that
process. Note that \predref{exe}{3} decodes the output and error separately,
one as an atom but the other as a string.

\begin{code}
exe(path(tee),
    [ '/dev/stderr'
    ],
    [ stdin(atom(你好, [encoding(utf8)])),
      stdout(atom(A, [encoding(utf8)])),
      stderr(string(B, [encoding(utf8)])),
      status(exit(0))
    ]).
\end{code}

\subsection{Implementation Notes}

Important to close the input stream immediately after writing and
during the call phase. Do \textbf{not} wait for the clean-up phase to close
the input stream, otherwise the process will never terminate. It
will hang while waiting for standard input to close, assuming the
sub-process reads the input.

This leads to a key caveat when using a single concurrent thread. A
single callee thread executes the primary read-write goals in
sequential order. The current implementation preserves the \arg{Options}
ordering. Hence output should always preceed input, i.e. writing to
standard input should go first before attempting to read from
standard output. Otherwise the sequence will block indefinitely. For
this reason, the number of concurrent threads matches the number of
concurrent goals. This abviates the sequencing of the goals because
all goals implicitly execute concurrently.

\begin{tags}
    \tag{To be done}
Take care when using the \verb$status(Status)$ option unless you have
\verb$stdin(null)$ on Windows because, for some sub-processes, the goals
never complete.
\end{tags}
\end{description}

\chapter{library(canny/files)}\label{sec:files}

\begin{description}
    \predicate[nondet]{absolute_directory}{2}{+Absolute, -Directory}
Finds the directories of \arg{Absolute} by walking up the absolute path
until it reaches the root. Operates on paths only; it does not check
that \arg{Absolute} actually exists. \arg{Absolute} can be a directory or file
path.

Fails if \arg{Absolute} is not an absolute file name, according to
\predref{is_absolute_file_name}{2}. Works correctly for Unix and Windows paths.
However, it finally unifies with the drive letter under Windows, and
the root directory (/) on Unix.

\begin{arguments}
\arg{Absolute} & specifies an absolute path name. On Windows it must
typically include a driver letter, else not absolute in the complete
sense under Microsoft Windows since its file system supports
multiple root directories on different mounted drives. \\
\end{arguments}
\end{description}

\chapter{library(canny/hdx)}\label{sec:hdx}

\begin{description}
    \predicate[semidet]{hdx}{4}{+StreamPair, +Term, -Codes, +TimeOut}
\nodescription
    \predicate[semidet]{hdx}{3}{+In, -Codes, +TimeOut}
\nodescription
    \predicate[semidet]{hdx}{2}{+Out, +Term}
Performs a single half-duplex stream interaction with \arg{StreamPair}.
Flushes \arg{Term} to the output stream. Reads pending \arg{Codes} from the
input stream within \arg{TimeOut} seconds. Succeeds when a write-read
cycle completes without timing out; fails on time-out expiry.

Filling a stream buffer blocks the calling thread if there is no
input ready. Pending read operations also block for the same reason.
Hence the \predref{wait_for_input}{3} \textbf{must} precede them.

\begin{arguments}
\arg{StreamPair} & connection from client to server, a
closely-associated input and output stream pairing used for
half-duplex communication. \\
\arg{Term} & to write and flush. \\
\arg{Codes} & waited for and extracted from the pending input stream. \\
\arg{TimeOut} & in seconds. \\
\end{arguments}
\end{description}

\chapter{library(canny/maths)}\label{sec:maths}

\begin{description}
    \predicate[det]{frem}{3}{+X:number, +Y:number, -Z:number}
\arg{Z} is the remainder after dividing \arg{X} by \arg{Y}, calculated by \arg{X} - N * \arg{Y}
where N is the nearest integral to \arg{X} / \arg{Y}.

    \predicate[det]{fmod}{3}{+X:number, +Y:number, -Z:number}
\arg{Z} is the remainder after dividing \arg{X} by \arg{Y}, equal to \arg{X} - N * \arg{Y} where N
is \arg{X} over \arg{Y} after truncating its fractional part.

    \predicate[semidet]{epsilon_equal}{2}{+X:number, +Y:number}
\nodescription
    \predicate[semidet]{epsilon_equal}{3}{+Epsilons:number, +X:number, +Y:number}
Succeeds only when the absolute difference between the two given
numbers \arg{X} and \arg{Y} is less than or equal to epsilon, or some factor
(\arg{Epsilons}) of epsilon according to rounding limitations.

    \predicate[det]{frexp}{3}{+X:number, -Y:number, -Exp:integer}
Answers mantissa \arg{Y} and exponent \arg{Exp} for floating-point number \arg{X}.

\begin{arguments}
\arg{Y} & is the floating-point mantissa falling within the interval
[0.5, 1.0). Note the non-inclusive upper bound. \\
\end{arguments}

    \predicate[det]{ldexp}{3}{+X:number, -Y:number, +Exp:integer}
Loads exponent. Multiplies \arg{X} by 2 to the power \arg{Exp} giving \arg{Y}. Mimics
the C math \verb$ldexp(x, exp)$ function.

Uses an unusual argument order. Ordering aligns \arg{X}, \arg{Y} and \arg{Exp} with
\predref{frexp}{3}. Uses \Spow{} rather than \Shat{} operator. \arg{Exp} is an integer.

\begin{arguments}
\arg{X} & is some floating-point value. \\
\arg{Y} & is \arg{X} times 2 to the power \arg{Exp}. \\
\arg{Exp} & is the exponent, typically an integer. \\
\end{arguments}
\end{description}

\chapter{library(canny/octet)}\label{sec:octet}

\begin{description}
    \predicate[semidet]{octet_bits}{2}{?Octet:integer, ?Fields:list}
Unifies integral eight-bit \arg{Octet} with a list of Value:Width terms
where the Width integers sum to eight and the Value terms unify with
the shifted bit values encoded within the eight-bit byte.

\begin{arguments}
\arg{Octet} & an eight-bit byte by another name. \\
\arg{Fields} & colon-separated value-width terms. The shifted value of
the bits comes first before the colon followed by its integer bit
width. The list of terms \textit{specify} an octet by sub-spans of bits, or
bit \textit{fields}. \\
\end{arguments}
\end{description}

\chapter{library(canny/pack)}\label{sec:pack}

\begin{description}
    \predicate[semidet]{load_pack_modules}{2}{+Pack, -Modules}
Finds and loads all Prolog module sources for \arg{Pack}. Also loads test
files having once loaded the pack. \arg{Modules} becomes a list of
successfully-loaded pack modules.

    \predicate[nondet]{load_prolog_module}{2}{+Directory, -Module}
Loads Prolog source recursively at \arg{Directory} for \arg{Module}. Does \textbf{not}
load non-module sources, e.g. scripts without a module. Operates
non-deterministically for \arg{Module}. Finds and loads all the modules
within a given directory; typically amounts to a pack root
directory. You can find the File from which the module loaded using
module properties, i.e. \verb$module_property(Module, file(File))$.
\end{description}

\chapter{library(canny/payloads): Local Payloads}\label{sec:payloads}

Apply and Property terms must be non-variable. The list below
indicates the valid forms of Apply, indicating determinism. Note that
only peek and pop perform non-deterministically for all thread-local
payloads.

\begin{shortlist}
    \item \const{reset} is det
    \item \const{push} is semi-det
    \item \verb$peek(Payload)$ is non-det
    \item \verb$pop(Payload)$ is non-det
    \item \verb$[Apply0|Applies]$ is semi-det
    \item \arg{Apply} is semi-det for payload
\end{shortlist}

Properties as follows.

\begin{shortlist}
    \item \verb$top(Property)$ is semi-det for payload
    \item \arg{Property} is semi-det for payload
\end{shortlist}

The first form \predref{top}{1} peeks at the latest payload once. It behaves
semi-deterministically for the top-most payload.\vspace{0.7cm}

\begin{description}
    \predicate[det]{payload}{1}{:PI}
Makes public multi-file apply-to and property-of predicates using
the predicate indicator \arg{PI} of the form M:Payload/\{ToArity, OfArity\}
where arity specifications define the arity or arities for a
payload. Defines predicates M:apply_to_Payload/ToArity and
M:property_of_Payload/OfArity for module M. Allows comma-separated
lists of arities.

    \predicate[nondet]{apply_to}{2}{+Apply, :To}
\nodescription
    \predicate[semidet]{apply_to}{2}{+Applies, :To}

\begin{arguments}
\arg{Applies} & is a list of \arg{Apply} terms. It succeeds when all its
\arg{Apply} terms succeed, and fails when the first one fails, possibly
leaving side effects if the apply-to predicate generates addition
effects; though typically not for mutation arity-3 apply-to
predicates. \\
\end{arguments}

    \predicate[nondet]{property_of}{2}{+Property, :Of}
Finds \arg{Property} of some payload where the second argument M:\arg{Of}
defines the module M and payload atom \arg{Of}.

\arg{Property} \predref{top}{1} peeks semi-deterministically at the top-most payload
for some given property.
\end{description}

\chapter{library(canny/permutations)}\label{sec:permutations}

\begin{description}
    \predicate[nondet]{permute_sum_of_int}{2}{+N:nonneg, -Integers:list(integer)}
Permute sum. Non-deterministically finds all combinations of integer
sums between 1 and \arg{N}. Assumes that 0\Sel{}\arg{N}. The number of possible
permutations amounts to 2-to-the-power of \arg{N}-1; for \arg{N}=3 there are
four as follows: 1+1+1, 1+2, 2+1 and 3.

    \predicate[nondet]{permute_list_to_grid}{2}{+List0:list, -List:list(list)}
Permutes a list to two-dimensional grid, a list of lists. Given an
ordered \arg{List0} of elements, unifies \arg{List} with all possible rows of
columns. Given \const{a}, \const{b} and \const{c} for example, permutes three rows of
single columns \const{a}, \const{b}, \const{c}; then \const{a} in the first row with \const{b} and
\const{c} in the second; then \const{a} and \const{b} in the first row, \const{c} alone in
the second; finally permutes \const{a}, \const{b}, \const{c} on a single row.
Permutations always preserve the order of elements from first to
last.
\end{description}

\chapter{library(canny/placeholders): Formatting Placeholders}\label{sec:placeholders}

\begin{tags}
    \tag{author}
Roy Ratcliffe
    \tag{version}
0.1.0
\end{tags}

This module provides predicates for formatting strings with placeholders.
Placeholders are specified in the form of \verb${name}$ within a format string.
The placeholders are replaced with corresponding values from a list of
options, where each option is specified as \verb$name(Value)$.
The result is an atom containing the formatted string.
The module uses DCG rules to parse the format string and replace the
placeholders with the corresponding values.

The main predicate is \predref{format_placeholders}{3}, which takes a format
string, an atom to hold the result, and a list of options. It processes
the format string, replacing placeholders with their corresponding values
from the options list. If a placeholder does not have a corresponding value,
it will fail.

The \predref{format_placeholders}{3} predicate formats a string with placeholders, while
\predref{format_placeholders}{4} allows for additional options to be returned; namely,
the remaining options after processing the placeholders.\vspace{0.7cm}

\begin{description}
    \predicate[det]{format_placeholders}{3}{+Format, -Atom, +Options}
\nodescription
    \predicate[det]{format_placeholders}{4}{+Format, -Atom, +Options, -RestOptions}
Formats a string with placeholders in the form of \verb${name}$. The
placeholders are replaced with corresponding values from the options
list. The result is an atom with the formatted string.

The \arg{Format} string can be any atom or string containing placeholders.
The \arg{Options} list should contain terms of the form \verb$name(Value)$, where
\const{name} is the placeholder name and \arg{Value} is the value to replace it
with. If a placeholder does not have a corresponding value in the
\arg{Options} list, it will not be replaced, and the placeholder will remain
in the resulting atom.

\begin{arguments}
\arg{Format} & The format string containing placeholders. \\
\arg{Atom} & The resulting atom with placeholders replaced. \\
\arg{Options} & The list of options containing values for placeholders. \\
\arg{RestOptions} & The remaining options after processing the placeholders. \\
\end{arguments}

    \dcg[det]{placeholders}{2}{-Terms, ?Options}
Formats a list of terms by replacing placeholders in the form of \verb${name}$
with corresponding values from the options list. The placeholders are
replaced with the values associated with the names in the options list.

The result is a list of atoms and values, and a completed options list.

\begin{arguments}
\arg{Terms} & The list of terms to be formatted. \\
\arg{Options} & The list of options containing values for placeholders. \\
\end{arguments}

    \dcg[det]{placeholders}{4}{+Terms0, -Terms, +Options0, -Options}
Processes a format string with placeholders using a list of terms
and options. The format string is the difference list of codes,
where placeholders are replaced with values from the options list.
The result is a list of atomics and an updated options list.

Scans the input, replacing placeholders of the form \verb${name}$ with
values from the options list. The result is a list of atoms and
values, and an updated options list. Uses DCG rules for flexible
parsing and substitution.

The resulting list of terms contains atoms and values, where each
placeholder is replaced with the corresponding value from the
options list. The options list is updated to include any new options
found in the format string.

Unifies the same placeholder with the same value in the options list if it
appears more than once. Placeholders can appear in the format string
multiple times, and each occurrence will be replaced with the same value.

\begin{arguments}
\arg{Terms0} & The initial list of terms to be processed. \\
\arg{Terms} & The resulting list of terms after processing. \\
\arg{Options0} & The initial list of options to be processed. \\
\arg{Options} & The resulting list of options after processing. \\
\end{arguments}
\end{description}

\chapter{library(canny/pop)}\label{sec:pop}

\begin{description}
    \predicate[det]{pop_lsbs}{2}{+A:nonneg, -L:list}
Unifies non-negative integer \arg{A} with its set bits \arg{L} in
least-significate priority order. Defined only for non-negative \arg{A}.
Throws a domain error otherwise.

\begin{tags}
    \tag{Errors}
\verb$domain_error(not_less_than_one, A)$ if \arg{A} less than 0.
\end{tags}
\end{description}

\chapter{library(canny/redis)}\label{sec:redis}

\begin{description}
    \predicate[det]{redis_last_streams}{2}{+Reads, -Streams:list}
\nodescription
    \predicate[det]{redis_last_streams}{3}{+Reads, ?Tag, -Streams:dict}
Collates the last \arg{Streams} for a given list of \arg{Reads}, the reply from
an XREAD command. The implementation assumes that each stream's read
reply has one entry at least, else the stream does not present a
reply.

    \predicate[semidet]{redis_last_stream_entry}{3}{+Entries, -StreamId, -Fields}
\nodescription
    \predicate[semidet]{redis_last_stream_entry}{4}{+Entries:list(list), -StreamId:atom, ?Tag:atom, -Fields:dict}
Unifies with the last \arg{StreamId} and \arg{Fields}. It fails for empty
\arg{Entries}. Each entry comprises a \arg{StreamId} and a set of \arg{Fields}.

    \predicate[det]{redis_keys_and_stream_ids}{4}{+Streams, ?Tag, -Keys, -StreamIds}
\nodescription
    \predicate[det]{redis_keys_and_stream_ids}{3}{+Pairs, -Keys, -StreamIds}
\arg{Streams} or \arg{Pairs} of \arg{Keys} and \arg{StreamIds}. Arity-3 exists with \arg{Tag} in
order to unify with a dictionary by \arg{Tag}.

\begin{arguments}
\arg{Streams} & is a dictionary of stream identifiers, indexed by
stream key. \\
\arg{Keys} & is a list of stream keys. \\
\arg{StreamIds} & is a list of corrected stream identifiers. The
predicate applies \predref{redis_stream_id}{3} to the incoming identifiers,
allowing for arbitrary milliseconds-sequence pairs including
implied missing zero sequence number. \\
\end{arguments}

    \predicate[nondet]{redis_stream_read}{4}{+Reads, -Key, -StreamId, -Fields}
\nodescription
    \predicate[nondet]{redis_stream_read}{5}{+Reads, -Key, -StreamId, ?Tag, -Fields}
Unifies with all \arg{Key}, \arg{StreamId} and array of \arg{Fields} for all \arg{Reads}.

\begin{arguments}
\arg{Reads} & is a list of [\arg{Key}, Entries] lists, a list of lists. The
sub-lists always have two items: the \arg{Key} of the stream followed by
another sub-list of stream entries. \\
\end{arguments}

    \predicate[nondet]{redis_stream_entry}{3}{+Entries, -StreamId, -Fields}
\nodescription
    \predicate[nondet]{redis_stream_entry}{4}{+Entries:list, -StreamId:pair(nonneg,nonneg), ?Tag:atom, -Fields:dict}
\nodescription
    \predicate[nondet]{redis_stream_entry}{5}{+Reads:list, -Key:atom, -StreamId:pair(nonneg,nonneg), ?Tag:atom, -Fields:dict}
Unifies non-deterministically with all \arg{Entries}, or \arg{Fields}
dictionaries embedded with multi-stream \arg{Reads}. Decodes the stream
identifier and the Entry.

\begin{arguments}
\arg{Entries} & is a list of [\arg{StreamId}, \arg{Fields}] lists, another list of
lists. Each sub-list describes an "entry" within the stream, a
pairing between an identifier and some fields. \\
\end{arguments}

    \predicate[semidet]{redis_stream_id}{1}{?RedisTimeSeqPair}
\nodescription
    \predicate[semidet]{redis_stream_id}{2}{?StreamId:text, ?RedisTimeSeqPair}
\nodescription
    \predicate[semidet]{redis_stream_id}{3}{?StreamId:text, ?RedisTime:nonneg, ?Seq:nonneg}
Stream identifier to millisecond and sequence numbers. In
practice, the numbers always convert to integers.

Deliberately validates incoming Redis time and sequence numbers.
Both must be integers and both must be zero or more. The predicates
fail otherwise. Internally, Redis stores stream identifiers as
128-bit unsigned integers split in half for the time and sequence
values, each of 64 bits.

The 3-arity version of the predicate handles extraction of time and
sequence integers from arbitrary stream identifiers: text or
compound terms, including implied zero-sequence stream identifier
with a single non-negative integer representing a millisecond Unix
time.

\begin{arguments}
\arg{StreamId} & identifies a stream message or entry, element or item.
All these terms apply to the contents of a stream, but Redis
internally refers to the content as \textit{entries}. \\
\arg{RedisTimeSeqPair} & is a pair of non-negative integers, time and
sequence. The Redis time equals Unix time multiplied by 1,000; in
other words, Unix time in milliseconds. \\
\end{arguments}

    \predicate[semidet]{redis_time}{1}{+RedisTime}
Successful when \arg{RedisTime} is a positive integer. Redis times amount
to millisecond-scale Unix times.

\begin{arguments}
\arg{RedisTime} & in milliseconds since 1970. \\
\end{arguments}

    \predicate[det]{redis_date_time}{3}{+RedisTime, -DateTime, +TimeZone}
Converts \arg{RedisTime} to \arg{DateTime} within \arg{TimeZone}.
\end{description}

\chapter{library(canny/redis_streams)}\label{sec:redisstreams}

\begin{description}
    \predicate[det]{xrange}{4}{+Redis, +Key:atom, -Entries:list, +Options:list}
Applies range selection to \arg{Key} stream. \arg{Options} optionally specify
the start and end stream identifiers, defaulting to \verb$-$ and \verb$+$
respectively or in reverse if \verb$rev(true)$ included in \arg{Options} list;
the plus stream identifier stands for the maximum identifier, or
the newest, whereas the minus identifier stands for the oldest.
Option \verb$count(Count)$ limits the number of entries to read by
\arg{Count} items.

The following always unifies \arg{Entries} with \verb$[]$.

\begin{code}
xrange(Server, Key, Entries, [start(+)]).
xrange(Server, Key, Entries, [rev(true), start(-)]).
\end{code}

    \predicate[semidet]{xread}{4}{+Redis, +Streams:dict, -Reads:list, +Options:list}
Unifies \arg{Reads} from \arg{Streams}. Fails on time-out, if option
\verb$block(Milliseconds)$ specifies a non-zero blocking delay.

\begin{arguments}
\arg{Reads} & by stream key. The reply has the form [Key, Entries]
for each stream where each member of Entries has the form
[StreamID, Fields] where Fields is an array of keys and values. \\
\end{arguments}

    \predicate[semidet]{xread_call}{5}{+Redis, +Streams, :Goal, -Fields, +Options}
\nodescription
    \predicate[semidet]{xread_call}{6}{+Redis, +Streams, :Goal, ?Tag, -Fields, +Options}
Reads \arg{Streams} continuously until \arg{Goal} succeeds or times out. Also
supports a \arg{Redis} time limit option so that blocking, if used, does
not continue indefinately even on a very busy stream set. The limit
applies to any of the given streams; it acts as a time threshold
for continuous blocking failures.
\end{description}

\chapter{library(canny/shifter)}\label{sec:shifter}

\begin{description}
    \predicate[semidet]{bit_shift}{3}{+Shifter, ?Left, ?Right}
Shifts bits left or right depending on the argument mode. Mode (+,
-, +) shifts left whereas mode (+, +, -) shifts right. The first
argument specifies the position of the bit or bits in \arg{Left}, the
second argument, while the third argument specifies the aligned
\arg{Right} bits. The shift moves in the direction of the variable
argument, towards the (-) mode argument.

The \arg{Shifter} argument provides three different ways to specify a bit
shift and bit width: either by an exclusive range using \verb$+$ and \verb$-$
terms; or an \textit{inclusive} range using \verb$:$ terms; or finally just a
single bit shift which implies a width of one bit. Colons operate
inclusively whereas plus and minus apply exclusive upper ranges.

It first finds the amount of Shift required and the bit Width. After
computing the lefthand and righthand bit masks, it finally performs
a shift-mask or mask-shift for left and right shifts respectively.

\begin{arguments}
\arg{Shifter} & is a Shift+Width, Shift-Width, High:Low, Low:High or
just a single integer Shift for single bits. \\
\arg{Left} & is the left-shifted integer. \\
\arg{Right} & is the right-shifted integer. \\
\end{arguments}
\end{description}

\chapter{library(canny/situations)}\label{sec:situations}

\begin{description}
    \predicate[nondet]{situation_apply}{2}{?Situation:any, ?Apply}
Mutates \arg{Situation}. \arg{Apply} term to \arg{Situation}, where \arg{Apply} is one of
the following. Note that the \arg{Apply} term may be nonground. It can
contain variables if the situation mutation generates new
information.

\begin{description}
    \termitem{module}{?Module}
Sets up \arg{Situation} using \arg{Module}. Establishes the dynamic
predicate options for the temporary situation module used for
persisting situation Now-At and Was-When tuples.

An important side effect occurs for ground \arg{Situation} terms. The
implementation creates the situation's temporary module and
applies default options to its new dynamic predicates. The
\verb$module(Module)$ term unifies with the newly-created or existing
situation module.

The predicate's determinism collapses to semi-determinism for
ground situations. Otherwise with variable \arg{Situation} components,
the predicate unifies with all matching situations, unifying
with \verb$module(Module)$ non-deterministically.
    \termitem{now}{+Now:any}
    \termitem{now}{+Now:any, +At:number}
Makes some \arg{Situation} become \arg{Now} for time index \arg{At}, at the next
fixation. Effectively schedules a pending update one or more
times; the next situation \verb$fix/0$ fixes the pending situation
changes at some future point. The \verb$now/1$ form applies \arg{Now} to
\arg{Situation} at the current Unix epoch time.

Uses \qpredref{canny}{apply_to_situation}{2} when \arg{Situation} is ground, but
uses \qpredref{canny}{property_of_situation}{2} otherwise. Asserts therefore
for multiple situations if \arg{Situation} comprises variables. You
cannot therefore have non-ground situations.
    \termitem{fix}{}
    \termitem{fix}{+Now:any}
Fixating situations does three important things. First, it adds
new Previous-When pairs to the situation history. They become
\verb$was/2$ dynamic facts (clauses without rules). Second, it adds,
replaces or removes the most current Current-When pair. This
allows detection of non-events, e.g. when something disappears.
Some types of situation might require such event edges. Finally,
fixating broadcasts situation-change messages.

The rule for fixing the Current-When pair goes like this: Is
there a new \verb$now/2$, at least one? The latest becomes the new
current. Any others become Previous-When. If there is no
\verb$now/2$, then the current disappears. Messages broadcast
accordingly. If there is more than one \verb$now/2$, only the latest
becomes current. Hence currently-previously only transitions
once in-between fixations.

Term \verb$fix/1$ is a shortcut for \verb$now(Now, At)$ and \const{fix} where \verb$At$
becomes the current Unix epoch time. Fixes but does not retract
history terms.
    \termitem{retract}{+When:number}
    \termitem{retract}{?When:number, +Delay:number}
Retracts all \verb$was/2$ clauses for all matching \arg{Situation} terms.
Term \verb$retract(_, Delay)$ retracts all \verb$was/2$ history terms using
the last term's latest time stamp. In this way, you can retract
situations without knowing their absolute time. For example, you
can retract everything older than 60 seconds from the last known
history term when you \verb$retract(_, 60)$.
\end{description}

The second argument \arg{Apply} can be a list of terms to apply, including
nested lists of terms. All terms apply in order first to last, and
depth first.

\begin{arguments}
\arg{Now} & is the state of a \arg{Situation} at some point in time. The Now
term must be non-variable but not necessarily ground. Dictionaries
with unbound tags can exist within the situation calculus. \\
\end{arguments}

    \predicate[nondet]{situation_property}{2}{?Situation:any, ?Property}
\arg{Property} of \arg{Situation}.

\begin{description}
    \termitem{module}{?Module}
Marries situation terms with universally-unique modules, one for
one. All dynamic situations link a situation term with a module.
This design addresses performance. Retracts take a long time,
relatively, especially for dynamic predicates with very many
clauses; upwards of 10,000 clauses for example. Note, you can
never delete the situation-module association, but you can
retract all the dynamic clauses belonging to a situation.
    \termitem{defined}{}
\arg{Situation} is defined whenever a unique situation module already
exists for the given \arg{Situation}. Amounts to the same as asking
for \verb$module(_)$ property.
    \termitem{currently}{?Current:any}
    \termitem{currently}{?Current:any, ?When:number}
    \termitem{currently}{Current:any, for(Seconds:number)}
Unifies with \arg{Current} for \arg{Situation} and When it happened. Unifies
with the one and only \arg{Current} state for all the matching
\arg{Situation} terms. Unifies non-deterministically for all \arg{Situation}
solutions, but semi-deterministically for \arg{Current} state. Thus
allows for multiple matching situations but only one \arg{Current}
solution.

You can replace the When term with \verb$for(Seconds)$ in order to
measure elapsed interval since fixing \arg{Situation}. Same applies to
\predref{previously}{2} except that the current situation time stamp serves
as the baseline time, else defaults to the current time.
    \termitem{previously}{?Previous:any}
    \termitem{previously}{?Previous:any, ?When:number}
    \termitem{previously}{Previous:any, for(Seconds:number)}
Finds \arg{Previous} state of \arg{Situation}, non-deterministically
resolving zero or more matching \arg{Situation} terms. Fails if no
previous \arg{Situation} condition.
    \termitem{history}{?History:list(compound)}
Unifies \arg{History} with all current and previous situation
conditions, including their time stamps. \arg{History} is a sequence
of compounds of the form \verb$was(Was, When)$ where \arg{Situation} is
effectively a primitive condition coordinate, Was is a sensing
outcome and When marks the moment that the outcome transpired.
\end{description}
\end{description}

\chapter{library(canny/situations_debugging)}\label{sec:situationsdebugging}

\begin{description}
    \predicate[det]{print_situation_history_lengths}{0}{}
Finds all situations. Samples their histories and measures the
history lengths. Uses \verb$=$ when sorting; do not remove duplicates.
Prints a table of situations by their history length, longest
history comes first. Filters out single-element histories for the
sake of noise minimisation.
\end{description}

\chapter{library(canny/z)}\label{sec:z}

\begin{description}
    \predicate[semidet]{enz}{2}{+Data:list, +File}
Zips \arg{Data} to \arg{File}. Writes \verb$zip(Name:atom, Info:dict, MemFile:memory_file)$ functor triples to \arg{File} where \arg{Name} is the
key; \arg{MemFile} is the content as a memory file. Converts the \arg{Info}
dictionary to new-member options when building up the zipper.
Ignores any non-valid key pairs, including offset plus compressed
and uncompressed sizes.

The implementation \textit{asserts} octet encoding for new files with a
zipper. The predicate for creating a zipper member does \textbf{not} allow
for an encoding option. It encodes as binary by default.

    \predicate[semidet]{unz}{2}{+File, -Data:list}
Unzips \arg{File} to \arg{Data}, a list of \const{zip} functors with \arg{Name} atom,
\arg{Info} dictionary and \arg{MemFile} content arguments.

You cannot apply \predref{unz}{2} to an empty zip \arg{File}. A bug crashes the
entire Prolog run-time virtual machine.
\end{description}

\chapter{library(data/frame)}\label{sec:frame}

\begin{description}
    \predicate[semidet]{columns_to_rows}{2}{?ListOfColumns, ?ListOfRows}
Transforms \arg{ListOfColumns} to \arg{ListOfRows}, where a row is a list of
key-value pairs, one for each cell. By example,

\begin{code}
[a=[1, 2], b=[3, 4]]
\end{code}

becomes

\begin{code}
[[a-1, b-3], [a-2, b-4]]
\end{code}

Else fails if rows or columns do not match. The output list of lists
suitably conforms to \predref{dict_create}{3} Data payloads from which you can
build dictionaries.

\begin{code}
?- columns_to_rows([a=[1, 2], b=[3, 4]], A),
   maplist([B, C]>>dict_create(C, row, B), A, D).
A = [[a-1, b-3], [a-2, b-4]],
D = [row{a:1, b:3}, row{a:2, b:4}].
\end{code}

\end{description}

\chapter{library(dcg/endian)}\label{sec:endian}

\begin{description}
    \dcg[semidet]{endian}{3}{?BigOrLittle, ?Width, ?Value}
Applies \const{big} or \const{little}-endian ordering grammar to an integer
\arg{Value} of any \arg{Width}.

Divides the problem in two: firstly the 'endianness' span which
unifies an input or output phrase with the bit width of a value, and
secondly the shifted bitwise-OR phase that translates between coded
eight-bit octets and un-encoded integers of unlimited bit width by
accumulation.

\begin{arguments}
\arg{BigOrLittle} & is the atom \const{big} or \const{little} specifying the
endianness of the coded \arg{Value}. \\
\arg{Width} & is the multiple-of-eight bit width of the endian-ordered
octet phrase. \\
\arg{Value} & is the un-encoded integer value of unlimited bit width. \\
\end{arguments}

    \dcg[semidet]{big_endian}{2}{?Width, ?Value}
Implements the grammar for \verb$endian(big, Width, Value)$ super-grammar.

In (-, +) mode the accumulator recurses \textit{first} and then the
residual \arg{Value}_ merges with the accumulated \arg{Value} because the first
octet code is the most-significant byte of the value for big-endian
integer representations, rather than the least-significant. The \verb$0 =< H, H =< 255$ guard conditions ensure failure for non-octet code
items in the list.

    \dcg[semidet]{little_endian}{2}{?Width, ?Value}
Implements \verb$endian(little, Width, Value)$ grammar.

Little-endian accumulators perform the same logical unification as
for big-endian only in reverse. The only difference between big and
little: recurse first or recurse last. Apart from that subtle but
essential difference, the inner computation behaves identically.
\end{description}

\chapter{library(dcg/files)}\label{sec:files}

\begin{description}
    \dcg[nondet]{directory_entry}{2}{+Directory, ?Entry}
Neatly traverses a file system using a grammar.

Finds files and skips the special dot entries. Here, \arg{Entry} refers
to a file. The grammar recursively traverses sub-directories beneath
the given \arg{Directory} and yields every existing file path at
\arg{Entry}. The directory acts as the root of the scan; it joins with
the entry to yield the full path of the file, but \textbf{not} with the
difference list. The second \arg{List} argument of \predref{phrase}{2} unifies
with a list of the corresponding sub-path components \textbf{without} the
root. The caller sees the full path \textbf{and} the relative
sub-components.

Note that the second clause appears in the DCG expanded form with the
two hidden arguments: the pre-parsed input list \arg{S0} and the
post-parsed output list \arg{S}. For non-directory entries, the input list
unifies with nil \verb$[]$ because it represents a terminal node in the
directory tree, and the post-parsed terms amount to the accumulated
\arg{Entries} spanning the sub-directory entries in-between the original
root directory and the file itself.

    \predicate[nondet]{directory_entry}{2}{+Directory, ?Entry}
Finds files and directories in the \arg{Directory} except special files: dot,
the current directory; and double dot, the parent directory.

No need to check if the \arg{Entry} exists. It does exist at the time of
directory iteration. That could easily change by deleting, moving or
renaming the entry.
\end{description}

\chapter{library(doc/latex)}\label{sec:latex}

\begin{description}
    \predicate[det]{latex_for_pack}{3}{+Spec, +OutFile, +Options}
\end{description}

\chapter{library(docker/random_names)}\label{sec:randomnames}

\begin{description}
    \predicate[nondet]{random_name}{1}{?Name}
Non-deterministically generates Docker-style random names. Uses
\predref{random_permutation}{2} and \predref{member}{2}, rather than \predref{random_member}{2}, in
order to generate all possible random names by back-tracking if
necessary.

The engine-based implementation has two key features: generates
random permutations of both left and right sub-names independently;
does not repeat until after unifying all permutations. This implies
that two consecutive names will never be the same up until the
boundary event between two consecutive randomisations. There is a
possibility, albeit small, that the last random name from one
sequence might accidentally match the first name in the next random
sequence. There are 23,500 possible combinations.

The implementation is \textbf{not} the most efficient, but does perform
accurate randomisation over all left-right name permutations.

Allows \arg{Name} to collapse to semi-determinism with ground terms
without continuous random-name generation since it will never match
an atom that does not belong to the Docker-random name set. The
engine-based non-determinism only kicks in when \arg{Name} unbound.

    \predicate[det]{random_name_chk}{1}{-Name:atom}
Generates a random \arg{Name}.

Only ever fails if \arg{Name} is bound and fails to match the next random
\arg{Name}, without testing for an unbound argument. That makes little
sense, so fails unless \arg{Name} is a variable.

    \predicate[semidet]{random_name_chk}{2}{?LHS:atom, ?RHS:atom}
Unifies \arg{LHS}-\arg{RHS} with one random name, a randomised selection from
all possible names.

Note, this does \textbf{not} naturally work in (+, ?) or (?, +) or (+, +)
modes, even if required. Predicate \predref{random_member}{2} fails
semi-deterministically if the given atom fails to match the
randomised selection. Unifies semi-deterministically for ground
atoms in order to work correctly for non-variable arguments. It
collapses to failure if the argument cannot unify with random-name
possibilities.
\end{description}

\chapter{library(gh/api): GitHub API}\label{sec:api}

\begin{tags}
    \tag{author}
Roy Ratcliffe
\end{tags}

You need a personal access token for updates. You do \textbf{not} require
them for public access.\vspace{0.7cm}

\begin{description}
    \predicate[det]{ghapi_update_gist}{4}{+GistID, +Data, -Reply, +Options}
Updates a Gist by its unique identifier. \arg{Data} is the patch payload
as a JSON object, or dictionary if you include \verb$json_object(dict)$ in
\arg{Options}. \arg{Reply} is the updated Gist in JSON on success.

The example below illustrates a Gist update using a JSON term.
Notice the doubly-nested \predref{json}{1} terms. The first sets up the HTTP
request for JSON while the inner term specifies a JSON \textit{object}
payload. In this example, the update adds or replaces the \verb$cov.json$
file with content of "\Scurl{}" as serialised JSON. Update requests for
Gists have a \const{files} object with a nested filename-object comprising
a content string for the new contents of the file.

\begin{code}
ghapi_update_gist(
    ec92ac84832950815861d35c2f661953,
    json(json([ files=json([ 'cov.json'=json([ content='{}'
                                             ])
                           ])
              ])), _, []).
\end{code}

\begin{tags}
    \tag{See also}
\url{https://docs.github.com/en/rest/reference/gists\#update-a-gist}
\end{tags}

    \predicate[det]{ghapi_get}{3}{+PathComponents, +Data, +Options}
Accesses the GitHub API. Supports JSON terms and dictionaries. For
example, the following goal accesses the GitHub Gist API looking for
a particular Gist by its identifier and unifies \arg{A} with a JSON term
representing the Gist's current contents and state.

\begin{code}
ghapi_get([gists, ec92ac84832950815861d35c2f661953], A, []).
\end{code}

Supports all HTTP methods despite the predicate name. The "get"
mirrors the underlying \predref{http_get}{3} method which also supports all
methods. POST and PATCH send data using the \predref{post}{1} option and
override the default HTTP verb using the \predref{method}{1} option.
Similarly here.

Handles authentication via settings, and from the system environment
indirectly. Option \predref{ghapi_access_token}{1} overrides both. Order of
overriding proceeds as: option, setting, environment, none. Empty
atom counts as none.

Abstracts away the path using path components. Argument
\arg{PathComponents} is an atomic list specifying the URL path.
\end{description}

\chapter{library(html/scrapes)}\label{sec:scrapes}

\begin{description}
    \predicate[nondet]{scrape_row}{2}{+URL, -Row}
Scrapes all table rows non-deterministically by row within each
table. Tables must have table headers, \const{thead} elements.

Scrapes distinct rows. Distinct is important because HTML documents
contain tables within tables within tables. Attempts to permit some
flexibility. Asking for sub-rows finds head sub-rows; catches and
filters out by disunifying data with heads.
\end{description}

\chapter{library(ieee/754)}\label{sec:754}

\begin{description}
    \predicate[det]{ieee_754_float}{3}{+Bits, ?Word, ?Float}
\nodescription
    \predicate[nondet]{ieee_754_float}{3}{-Bits, ?Word, ?Float}
Performs two-way pack and unpack for IEEE 754 floating-point numbers
represented as words.

Not designed for performance. Uses CLP(FD) for bit manipulation. and
hence remains within the integer domain. \arg{Float} arithmetic applies
outside the finite-domain constraints.

\begin{arguments}
\arg{Word} & is a non-negative integer. This implementation does not
handle negative integers. Negative support implies a non-determinate
solution for packing. A positive and negative answer exists for any
given \arg{Float}. \\
\arg{Sig} & is the floating-point significand between plus and minus 1.
Uses Sig rather than Mantissa; Sig short for Significand, another
word for mantissa. \\
\end{arguments}
\end{description}

\chapter{library(linear/algebra): Linear algebra}\label{sec:algebra}

"The introduction of numbers as coordinates is an act of
violence."--Hermann Weyl, 1885-1955.

Vectors are just lists of numbers, or scalars. These scalars apply to
arbitrary abstract dimensions. For example, a two-dimensional vector
[1, 2] applies two scalars, 1 and 2, to dimensional units \textit{i} and
\textit{j}; known as the basis vectors for the coordinate system.

Is it possible, advisable, sensible to describe vector and matrix
operations using Constraint Logic Programming (CLP) techniques? That
is, since vectors and matrices are basically columns and rows of
real-numeric scalars, their operators amount to constrained
relationships between real numbers and hence open to the application
of CLP over reals. The simple answer is yes, the linear_algebra
predicates let you express vector operators using real-number
constraints.

Constraint logic adds some important features to vector operations.
Suppose for instance that you have a simple addition of two vectors,
a vector translation of U+V=W. Add U to V giving W. The following
statements all hold true. Note that the CLP-based translation unifies
correctly when W is unknown but also when U or V is unknown. Given
any two, you can ask for the missing vector.

\begin{code}
?- vector_translate([1, 1], [2, 2], W).
W = [3.0, 3.0] ;
false.
?- vector_translate([1, 1], V, [3, 3]).
V = [2.0, 2.0] ;
false.
?- vector_translate(U, [2, 2], [3, 3]).
U = [1.0, 1.0] ;
false.
\end{code}

Note also that the predicate answers non-deterministically with
back-tracking until no alternative answer exists. This presumes that
alternatives could exist at least in theory if not in practice.
Trailing choice-points remain unless you cut them.\vspace{0.7cm}

\begin{description}
    \predicate[semidet]{matrix_dimensions}{3}{?Matrix:list(list(number)), ?Rows:nonneg, ?Columns:nonneg}
Dimensions of \arg{Matrix} where dimensions are \arg{Rows} and \arg{Columns}.

A matrix of M rows and N columns is an M-by-N matrix. A matrix with
a single row is a row vector; one with a single column is a column
vector. Because the linear_algebra module uses lists to represent
vectors and matrices, you need never distinguish between row and
column vectors.

Boundary cases exist. The dimensions of an empty matrix \Snil{} equals
[0, _] rather than [0, 0]. And this works in reverse; the matrix
unifying with dimensions [0, _] equals [].

    \predicate[semidet]{matrix_identity}{2}{+Order:nonneg, -Matrix:list(list(number))}
\arg{Matrix} becomes an identity matrix of \arg{Order} dimensions. The result is
a square diagonal matrix of \arg{Order} rows and \arg{Order} columns.

The first list of scalars (call it a row or column) becomes 1
followed by \arg{Order}-1 zeros. Subsequent scalar elements become an
\arg{Order}-1 identity matrix with a 0-scalar prefix for every sub-list.
Operates recursively albeit without tail recursion.

Fails when matrix size \arg{Order} is less than zero.

    \predicate[semidet]{matrix_transpose}{2}{?Matrix0:list(list(number)), ?Matrix:list(list(number))}
Transposes matrices. The matrix is a list of lists. Fails unless all
the sub-lists share the same length. Works in both directions, and
works with non-numerical elements. Only operates at the level of
two-dimensional lists, a list with sub-lists. Sub-sub-lists remain
lists and un-transposed if sub-lists comprise list elements.

    \predicate[nondet]{matrix_rotation}{2}{?Theta:number, ?Matrix:list(list(number))}
The constructed matrix applies to column vectors [X, Y] where
positive \arg{Theta} rotates X and Y anticlockwise; negative rotates
clockwise. Transpose the rotation matrix to reverse the angle of
rotation; positive for clockwise, negative anticlockwise.

    \predicate[semidet]{vector_distance}{2}{?V:list(number), ?Distance:number}
\nodescription
    \predicate[semidet]{vector_distance}{3}{?U:list(number), ?V:list(number), ?Distance:number}
\arg{Distance} of the vector \arg{V} from its origin. \arg{Distance} is Euclidean
distance between two vectors where the first vector is the origin.
Note that Euclidean is just one of many distances, including
Manhattan and chessboard, etc. The predicate is called distance,
rather than length. The term length overloads on the dimension of a
vector, its number of numeric elements.

    \predicate[nondet]{vector_translate}{3}{?U, ?V, ?W}
Translation works forwards and backwards. Since \arg{U}+\arg{V}=\arg{W} it follows
that \arg{U}=\arg{W}-\arg{V} and also \arg{V}=\arg{W}-\arg{U}. So for unbound \arg{U}, the vector becomes \arg{W}-\arg{V}
and similarly for \arg{V}.

    \predicate[nondet]{vector_scale}{3}{?Scalar:number, ?U:list(number), ?V:list(number)}
Vector \arg{U} scales by \arg{Scalar} to \arg{V}.

What is the difference between multiply and scale? Multiplication
multiplies two vectors whereas scaling multiplies a vector by a
scalar; hence the verb to scale. Why is the scalar at the front of
the argument list? This allows the meta-call of \verb$vector_scale(Scalar)$
passing two vector arguments, e.g. when mapping lists of vectors.

The implementation performs non-deterministically because the CLP(R)
library leaves a choice point when searching for alternative
arithmetical solutions.

    \predicate[semidet]{vector_heading}{2}{?V:list(number), ?Heading:number}
\arg{Heading} in radians of vector \arg{V}. Succeeds only for two-dimensional
vectors. Normalises the \arg{Heading} angle in (+, -) mode; negative
angles wrap to the range between pi and two-pi. Similarly,
normalises the vector \arg{V} in (-, +) mode; \arg{V} has unit length.

    \predicate[nondet]{scalar_power}{3}{?X:number, ?Y:number, ?Z:number}
\arg{Z} is \arg{Y} to the power \arg{X}.

The first argument \arg{X} is the exponent rather than \arg{Y}, first rather
than second argument. This allows you to curry the predicate by
fixing the first exponent argument. In other words, \verb$scalar_power(2, A, B)$ squares A to B.
\end{description}

\chapter{library(ollama/chat): Ollama Chat}\label{sec:chat}

Idiomatic SWI-Prolog HTTP client module for interacting with an Ollama
chat API.

\section{Usage}

How to use and abuse the interface? Take some examples. The following
queries run with HTTP debugging enabled. Notice the headers.

For streaming:

\begin{code}
?- ollama_chat([_{role:user, content:"Hello"}], Message, [stream(true)]).
% http_open: Connecting to localhost:11434 ...
%       ok <stream>(000001a4454d2630) ---> <stream>(000001a4454d2740)
% HTTP/1.1 200 OK
% Content-Type: application/x-ndjson
% Date: Sat, 31 May 2025 10:48:49 GMT
% Connection: close
% Transfer-Encoding: chunked
Message = _{content:" Hello", role:"assistant"} ;
Message = _{content:"!", role:"assistant"} ;
Message = _{content:" How", role:"assistant"} ;
Message = _{content:" can", role:"assistant"} ;
Message = _{content:" I", role:"assistant"} ;
Message = _{content:" assist", role:"assistant"} ;
Message = _{content:" you", role:"assistant"} ;
Message = _{content:" today", role:"assistant"} ;
Message = _{content:"?", role:"assistant"} ;
Message = _{content:"", role:"assistant"}.
\end{code}

The streaming content type is \textbf{not} "application/json" but rather
newline-delimited JSON. This is correct. Our addition to the JSON type
multifile predicate catches this.

For non-streaming:

\begin{code}
?- ollama_chat([_{role:user, content:"Hello"}], Message, [stream(false)]).
% http_open: Connecting to localhost:11434 ...
%       ok <stream>(000001a4454d3ea0) ---> <stream>(000001a4454d4e90)
% HTTP/1.1 200 OK
% Content-Type: application/json; charset=utf-8
% Date: Sat, 31 May 2025 10:50:04 GMT
% Content-Length: 347
% Connection: close
Message = _{content:" Sure, I'm here to help! How can I assist you today?", role:"assistant"}.
\end{code}

\vspace{0.7cm}

\begin{description}
    \predicate[nondet]{ollama_chat}{3}{+Messages:list(dict), -Message:dict, +Options:list}
Leverages SWI-Prolog's HTTP libraries for Ollama chat API
interaction. To stream or not to stream? That becomes an option,
specify either \verb$stream(true)$ or \verb$stream(false)$, defaulting to
streaming. This option selects the predicate's determinism.
Predicate \predref{ollama_chat}{3} becomes non-deterministic \textbf{when}
streaming, but falls back to deterministic when not.

Pulls out the message from the reply; it becomes the result of the
chat interaction: many messages in, one message out. Taking only the
message assumes that the other keys within the reply dictionary have
less value. Callers can usually ignore them. The predicate unifies
with \verb$reply(Reply)$ in the \arg{Options} argument if the caller wants to
view the detailed response information.

Assumes that the reply is always a dictionary type without first
checking. The implementation relies on the lower-level HTTP layers
for parsing and rendering the correct term type. It also assumes
that the dictionary always contains a "message" pair. Throws an
exception when this presumption fails; this is a design feature
because all responses must have a message.
\end{description}

\chapter{library(os/apps): Operation system apps}\label{sec:apps}

What is an app? In this operating-system \verb$os_apps$ module context,
simply something you can start and stop using a process. It has no
standard input, and typically none or minimal standard output and
error.

There is an important distinction between apps and processes. These
predicates use processes to launch apps. An application typically has
one process instance; else if not, has differing arguments to
distinguish one running instance of the app from another. Hence for
the same reason, the app model here ignores "standard input." Apps
have no such input stream, conceptually speaking.

Is "app" the right word to describe such a thing? English limits the
alternatives: process, no because that means something that loads an
app; program, no because that generally refers the app's image
including its resources.

\section{App configuration}

Apps start by creating a process. Processes have four distinct
specification parameter groups: a path specification, a list of
arguments, possibly some execution options along with some optional
encoding and other run-time related options. Call this the
application's configuration.

The \verb$os_apps$ predicates rely on multi-file \qpredref{os}{property_for_app}{2} to
configure the app launch path, arguments and options. The
property-for-app predicate supplies an app's configuration
non-deterministically using three sub-terms for the first Property
argument, as follows.

\begin{shortlist}
    \item os:\verb$property_for_app(path(Path), App)$
    \item os:\verb$property_for_app(argument(Argument), App)$
    \item os:\verb$property_for_app(option(Option), App)$
\end{shortlist}

Two things to note about these predicates; (1) App is a compound
describing the app \textbf{and} its app-specific configuration information;
(2) the first Property argument collates arguments and options
non-deterministically. Predicate \predref{app_start}{1} finds all the argument-
and option-solutions \textit{in the order defined}.

\section{Start up and shut down}

By default, starting an app does \textbf{not} persist the app. It does not
restart if the user or some other agent, including bugs, causes the
app to exit. Consequently, this module offers a secondary
app-servicing layer. You can start up or shut down any app. This
amounts to starting and upping or stopping and downing, but
substitutes shut for stop. Starting up issues a start but also
watches for stopping.

\section{Broadcasts}

Sends three broadcast messages for any given App, as follows:

\begin{shortlist}
    \item os:\verb$app_started(App)$
    \item os:\verb$app_decoded(App, stdout(Codes))$
    \item os:\verb$app_decoded(App, stderr(Codes))$
    \item os:\verb$app_stopped(App, Status)$
\end{shortlist}

Running apps send zero or more os:\verb$app_decoded(App, Term)$ messages,
one for every line appearing in their standard output and standard
error streams. Removes line terminators. App termination broadcasts
an \verb$exit(Code)$ term for its final Status.

\section{Usage}

You can start or stop an app.

\begin{code}
app_start(App)
app_stop(App)
\end{code}

App is some compound that identifies which app to start and stop. You define an
App using \qpredref{os}{property_for_app}{2} multi-file predicate. You must at least define
an app's path using, as an example:

\begin{code}
os:property_for_app(path(path(mspaint)), mspaint) :- !.
\end{code}

Note that the Path is a path Spec used by \predref{process_create}{3}, so can include a
path-relative term as above. This is enough to launch the Microsoft Paint app on
Windows. No need for arguments and options for this example. Starting a \textit{running}
app does not start a new instance. Rather, it succeeds for the existing
instance. The green cut prevents unnecessary backtracking.

You can start and continuously restart apps using \predref{app_up}{1}, and subsequently
shut them down with \predref{app_down}{1}.

\subsection{Apps testing}

On a Windows system, try the following for example. It launches Microsoft Paint.
Exit the Paint app after \predref{app_up}{1} below and it will relaunch automatically.

\begin{code}
?- [library(os/apps), library(os/apps_testing)].
true.

?- app_up(mspaint).
true.

?- app_down(mspaint).
true.
\end{code}

\vspace{0.7cm}

\begin{description}
    \predicate[nondet]{app_property}{2}{?App:compound, ?Property}
\arg{Property} of \arg{App}.

Note that \verb$app_property(App, defined)$ should \textbf{not} throw an
exception. Some apps have an indeterminate number of invocations
where \arg{App} is a compound with variables. Make sure that the necessary
properties are ground, rather than unbound.

Collapses non-determinism to determinism by collecting \arg{App} and
\arg{Property} pairs before expanding the bag to members
non-deterministically.

    \predicate[nondet]{app_start}{1}{?App:compound}
Starts an \arg{App} if not already running. Starts more than one apps
non-deterministically if \arg{App} binds with more than one specifier.
Does not restart the app if launching fails. See \predref{app_up}{1} for
automatic restarts. An app's argument and option properties execute
non-deterministically.

Options can include the following:

\begin{description}
    \termitem{encoding}{Encoding}
an encoding option for the output and error streams.
    \termitem{alias}{Alias}
an alias prefix for the detached watcher thread.
\end{description}

Checks for not-running \textbf{after} unifying with the \arg{App} path. Succeeds
if already running.

    \predicate[nondet]{app_stop}{1}{?App:compound}
Kills the \arg{App} process. Stopping the app does not prevent subsequent
automatic restart.

Killing does \textbf{not} retract the \predref{app_pid}{2} by design. Doing so would
trigger a failure warning. (The waiting PID-monitor thread would die
on failure because its retract attempt fails.)

    \predicate[nondet]{app_up}{1}{?App:compound}
Starts up an \arg{App}.

Semantics of this predicate rely on \predref{app_start}{1} succeeding even if
already started. That way, you can start an app then subsequently
\textit{up} it, meaning stay up. Hence, you can \verb$app_stop(App)$ to force a
restart if already \verb$app_up(App)$. Stopping an app does not \textit{down} it!

Note that \predref{app_start}{1} will fail for one of two reasons: (1) because
the \arg{App} has not been defined yet; (2) because starting it fails for
some reason.

    \predicate[nondet]{app_down}{1}{?App:compound}
Shuts down an \arg{App}. Shuts down multiple apps non-deterministically if
the \arg{App} compound matches more than one app definition.
\end{description}

\chapter{library(os/lc)}\label{sec:lc}

\begin{description}
    \predicate[det]{lc_r}{1}{+Extensions:list}
Recursively counts and prints a table of the number of lines within
read-access files having one of the given \arg{Extensions} found in the
current directory or one of its sub-directories. Prints the results
in line-count descending order with the total count appearing first
against an asterisk, standing for all lines counted.

    \predicate[det]{lc_r}{2}{-Pairs, +Options}
Counts lines in files recursively within the current directory.

    \predicate[det]{lc_r}{3}{+Directory, -Pairs, +Options}
Counts lines within files starting at \arg{Directory}.

    \predicate[det]{lc}{3}{+Directory, -Pairs, +Options}
Counts lines in files starting at \arg{Directory} and using \arg{Options}.
Counts for each file concurrently in order to maintain high
performance.

\begin{arguments}
\arg{Pairs} & is a list of atom-integer pairs where the relative path
of a matching text file is the first pair-element, and the number of
lines counted is the second pair-element. \\
\end{arguments}
\end{description}

\chapter{library(os/search_paths)}\label{sec:searchpaths}

\begin{description}
    \predicate[det]{search_path_prepend}{2}{+Name:atom, +Directory:atom}
Adds \arg{Directory} to a search-path environment variable. Note, this is
not naturally an atomic operation but the prepend makes it thread
safe by wrapping the fetching and storing within a mutex.

Prepends \arg{Directory} to the environment search path by \arg{Name}, unless
already present. Uses semi-colon as the search-path separator on
Windows operating systems, or colon everywhere else. Adds \arg{Directory}
to the start of an existing path. Makes \arg{Directory} the first and only
directory element if the search path does not yet exist.

Note that \arg{Directory} should be an operating-system compatible search
path because non-Prolog software needs to search using the included
directory paths. Automatically converts incoming directory paths to
operating-system compatible paths.

Note also, the environment variable \arg{Name} is case insensitive on
Windows, but not so on Unix-based operating systems.

    \predicate[semidet]{search_path}{2}{+Name:atom, -Directories:list(atom)}
\nodescription
    \predicate[det]{search_path}{2}{+Name:atom, +Directories:list(atom)}
Only fails if the environment does \textbf{not} contain the given
search-path variable. Does not fail if the variable does \textbf{not}
identify a proper separator-delimited variable.

    \predicate[semidet]{search_path_separator}{1}{?Separator:atom}
\arg{Separator} used for search paths: semi-colon on the Microsoft Windows
operating system; colon elsewhere.
\end{description}

\chapter{library(os/windows): Microsoft Windows Operating System}\label{sec:windows}

By design, the following extensions for Windows avoid underscores
in order not to clash with existing standard paths, e.g. \verb$app_path$
which Prolog defines by default.

\begin{code}
userprofile
onedrive
onedrivecommercial
onedrivepersonal
programfiles
temp
documents
savedgames
appdata
applocal
localprograms
\end{code}

\vspace{0.7cm}\chapter{library(paxos/http_handlers): Paxos HTTP Handlers}\label{sec:httphandlers}

These handlers spool up a JSON-based HTTP interface to the Paxos
predicates, namely

\begin{itemize}
    \item \predref{paxos_property}{1} as JSON object on GET at /paxos/properties,
    \item \predref{paxos_get}{2} as arbitrary JSON on GET at /paxos/Key and
    \item \predref{paxos_set}{2} as arbitrary JSON on POST at /paxos/Key
\end{itemize}

Take the example below. Uses \predref{http_server}{1} to start a HTTP server
on some given port.

\begin{code}
?- [library(http/http_server), library(http/http_client)].
true.

?- http_server([port(8080)]).
% Started server at http://localhost:8080/
true.

?- http_get('http://localhost:8080/paxos/properties', A, []).
A = json([node=0, quorum=1, failed=0]).
\end{code}

Getting and setting using JSON encoding works as follows.

\begin{code}
?- http_get('http://localhost:8080/paxos/hello', A, [status_code(B)]).
A = '',
B = 204.

?- http_post('http://localhost:8080/paxos/hello', json(world), A, []).
A = @true.

?- http_get('http://localhost:8080/paxos/hello', A, [status_code(B)]).
A = world,
B = 200.
\end{code}

Note that the initial GET fails. It replies with the empty atom since no
content exists. Predicate \predref{paxos_get}{2} is semi-deterministic; it can
fail. Empty atom is not valid Prolog-encoding for JSON. Status code of
204 indicates no content. The Paxos ledger does not contain data for
that key.

Thereafter, POST writes a string value for the key and a repeated GET
attempt now answers the new consensus data. Status code 200 indicates a
successful ledger concensus.

\section{Serialisation}

Serialises unknowns. Paxos ledgers may contain non-JSON compatible data.
Anything that does not correctly serialise as JSON becomes an atomicly
rendered Prolog term. Take a consensus value of term \verb$a(1)$ for example;
GET requests see "\verb$a(1)$" as a rendered Prolog string. The ledger
comprises Prolog terms, fundamentally, rather than JSON-encoded strings.

Setting a Paxos value reads JSON from the POST request body. It can be
any valid JSON value including atomic values as well as objects and
arrays.\vspace{0.7cm}\chapter{library(paxos/udp_broadcast): Paxos on UDP}\label{sec:udpbroadcast}

Sets up Paxos over UDP broadcast on port 20005. Hooks up Paxos messaging
to UDP broadcast bridging using the \const{paxos} scope.

Initialisation order affects success. First initialises UDP
broadcasting then initialises Paxos. The result is two additional
threads: the UDP inbound proxy and the Paxos replicator.

You can override the UDP host, port and broadcast scope. Load settings
first if you want to override using file-based settings. Back-up
defaults derive from the environment and finally fall on hard-wired
values of 0.0.0.0, port 20005 via \const{paxos} scope. You can also override
the automatic Paxos node ordinal; it defaults to -1 meaning automatic
discovering of unique node number. Numbers start at 0 and increase by
one, translating to binary power indices for the quorum bit mask.

Note that environment defaults require upper-case variable names for
Linux. Variable names match case-sensitively on Unix platforms.

\section{Docker Stack}

For Docker in production mode, your nodes want to interact using the UDP
broadcast port. This port is not automatically available unless you
publish it. See example snippet below. The \const{ports} setting lists port
20005 for UDP broadcasts across the stack.

\begin{code}
version: "3"

services:

  my-service:
    image: my/image
    ports:
      - 20005:20005/udp
      - 8080:8080/tcp
\end{code}

\vspace{0.7cm}\chapter{library(print/(table))}\label{sec:table}

\begin{description}
    \predicate[det]{print_table}{1}{:Goal}
\nodescription
    \predicate[det]{print_table}{2}{:Goal, +Variables:list}
Prints all the variables within the given non-deterministic \arg{Goal}
term formatted as a table of centre-padded columns to
\verb$current_output$. One \arg{Goal} solution becomes one line of text.
Solutions to free variables become printed cells.

Makes an important assumption: that codes equate to character
columns; one code, one column. This will be true for most languages
on a teletype like terminal. Ignores any exceptions by design.

\begin{code}
?- print_table(user:prolog_file_type(_, _)).
+------+----------+
|  pl  |  prolog  |
|prolog|  prolog  |
| qlf  |  prolog  |
| qlf  |   qlf    |
| dll  |executable|
+------+----------+
\end{code}

\end{description}

\chapter{library(proc/loadavg)}\label{sec:loadavg}

\begin{description}
    \dcg[semidet]{loadavg}{5}{-Avg1, -Avg5, -Avg15, -RunnablesRatio, -LastPID}
Parses the Linux \verb$/proc/loadavg$ process pseudo-file. One space
separates all fields except the runnable processes and total
processes, a forward slash separates these two figures.

Load-average statistics comprise: three floating point numbers, one
integer ratio and one process identifier.

\begin{itemize}
    \item Load average for last minute
    \item Load average for last five minutes
    \item Load average for last 15 minutes
    \item Number of currently-runnable processes, meaning either
actually running or ready to run
    \item Total number of processes
    \item Last created process identifier
\end{itemize}

It follows logically that runnable processes is always less than or
equal to total processes.

One space separates all fields except the runnable processes and
total processes, a forward slash separates these two figures. The
implementation applies this requirement explicitly. The grammar
fails if more than one space exists, or if finds the terminating
newline missing. This approach allows you to reverse the grammar to
generate the load-average codes from the load-average figures.

    \predicate[det]{loadavg}{5}{-Avg1, -Avg5, -Avg15, -RunnablesRatio, -LastPID}
Captures and parses the current processor load average statistics on
Linux systems. Does \textbf{not} work on Windows systems.

\begin{tags}
    \tag{throws}
\verb$existence_error(source_sink, '/proc/loadavg')$ on Windows, or
other operating systems that do not have a \const{proc} subsystem.
\end{tags}
\end{description}

\chapter{library(random/temporary)}\label{sec:temporary}

\begin{description}
    \predicate[nondet]{random_temporary_module}{1}{-M:atom}
Finds a module that does not exist. Makes it exist. The new module
has a module class of temporary. Operates non-deterministically by
continuously generating a newly unique temporary module. Surround
with \predref{once}{1} when generating just a single module.

Utilises the \predref{uuid}{1} predicate which never fails; the implementation
relies on that prerequisite. Nor does \predref{uuid}{1} automatically generate
a randomly \textit{unique} identifier. The implementation repeats on
failure to find a module that does not already exist. If the
generation of a new unique module name always fails, the predicate
will continue an infinite failure-driven loop running until
interrupted within the calling thread.

The predicate allows for concurrency by operating a mutex across the
clauses testing for an existing module and its creation. Succeeds
only for mode (-).
\end{description}

\chapter{library(read/until)}\label{sec:until}

\begin{description}
    \predicate[nondet]{read_stream_to_codes_until_end_of_file}{2}{+In, -Codes}
\nodescription
    \predicate[nondet]{read_stream_to_codes_until}{3}{+In, -Codes, +Until}
Reads \arg{Codes} from a stream until it finds a specific code term, such
as \verb$end_of_file$. The predicate reads the stream until it encounters
the \arg{Until} code term, which defaults to \verb$end_of_file$. It succeeds
non-deterministically for each chunk read before reaching the
\arg{Until} code term. Use this predicate to process multiple messages
or data chunks from a stream, handling each chunk separately. The
\arg{Codes} variable contains the codes read from the stream, and the
predicate succeeds until it reaches the \arg{Until} condition.

\begin{arguments}
\arg{In} & The input stream to read from. \\
\arg{Codes} & The codes read from the stream. \\
\arg{Until} & The code term that terminates the reading. \\
\end{arguments}
\end{description}

\chapter{library(scasp/just_dot)}\label{sec:justdot}

\begin{description}
    \predicate[det]{scasp_just_dot_print}{3}{+Stream, +Src, +Options}
Reads a JSON file from \arg{Src}, which is expected to be in the format
produced by the \verb$s(CASP)$ solver, and prints a DOT representation of the
justification graph to the specified \arg{Stream}. The \arg{Options} parameter
allows customisation of the output, such as indentation size, graph
direction, background colour, node attributes, edge attributes, and
nodes to elide.

The JSON source should contain a dictionary with the following structure,
simplified for clarity:

\begin{code}
{
    "solver": {...},
    "query": {...},
    "answers": [
        {
            "bindings": {...},
            "model": [{"truth": ..., "value": {...}}],
            "tree": {
                "node": {"value": {...}},
                "children": [
                    {
                        "node": {"value": {...}},
                        "children": [...]
                    },
                    ...
                ]
            }
        },
        ...
    ]
}
\end{code}

The \const{answers} field is a list of answers, each containing bindings, a
model, and a tree structure. The \const{tree} field represents the
justification tree, where each node has a value and may have children,
forming a hierarchical structure of implications.

The output is a DOT graph representation of the justification tree,
where each node corresponds to a term in the justification, and edges
represent implications between nodes. The graph is directed, with arrows
indicating the direction of implications from one node to another.

The output is formatted as a DOT graph, which can be visualised using
graph visualisation tools like Graphviz. The output can be customised
using the \arg{Options} parameter, which allows for setting various attributes
of the graph, such as:

\begin{itemize}
    \item \verb$tab(Width)$: Specifies the indentation width for the output.
    \item \verb$rankdir(Direction)$: Sets the direction of the graph layout, e.g.
'LR' for left-to-right.
    \item \verb$bgcolor(Color)$: Sets the background colour of the graph.
    \item \verb$node(Attributes)$: Specifies attributes for the nodes in the graph.
    \item \verb$edge(Attributes)$: Specifies attributes for the edges in the graph.
    \item \verb$elides(Nodes)$: A list of nodes to elide in the graph, meaning they
will not be displayed.
\end{itemize}

This predicate is useful for visualising the justification structure of
\verb$s(CASP)$ queries, making it easier to understand the relationships
between different terms and their implications in the context of logic
programming and answer set programming.
\end{description}

\chapter{library(swi/atoms)}\label{sec:atoms}

\begin{description}
    \predicate[semidet]{restyle_identifier_ex}{3}{+Style, +Text, ?Atom}
Restyles \arg{Text} to \arg{Atom}. Predicate \predref{restyle_identifier}{3} fails for
incoming text with leading underscore. Standard
\qpredref{atom}{restyle_identifier}{3} fails for '_' because underscore fails for
\verb$atom_codes('_', [Code])$, \verb$code_type(Code, prolog_symbol)$. Underscore
(code 95) is a Prolog variable start and identifier continuation
symbol, not a Prolog symbol.

Strips any leading underscore or underscores. Succeeds only for
text, including codes, but does not throw.

\begin{arguments}
\arg{Text} & string, atom or codes. \\
\arg{Atom} & restyled. \\
\end{arguments}

    \predicate[nondet]{prefix_atom_suffix}{4}{?Prefix, ?Atom0, ?Suffix, ?Atom}
Non-deterministically unifies \arg{Prefix}, \arg{Atom0} and \arg{Suffix} with \arg{Atom}.
Applies two \predref{atom_concat}{3} predicates in succession. Unifies from
prefix to suffix for modes (?, ?, ?, -) else backwards from suffix
to prefix. Empty atom is a valid atom and counts as a \arg{Prefix}, \arg{Suffix}
or any other argument if unbound.
\end{description}

\chapter{library(swi/codes)}\label{sec:codes}

\begin{description}
    \predicate[semidet]{split_lines}{2}{?Codes, ?Lines:list(list)}
Splits \arg{Codes} into \arg{Lines} of codes, or vice versa. \arg{Lines} split by
newlines. The last line does not require newline termination. The
reverse unification however always appends a trailing newline to the
last line.
\end{description}

\chapter{library(swi/compounds)}\label{sec:compounds}

\begin{description}
    \predicate[semidet]{flatten_slashes}{2}{+Components0:compound, ?Components:compound}
Flattens slash-delimited components. \arg{Components0} unifies flatly with
\arg{Components} using \verb$mode(+, ?)$. Fails if \arg{Components} do not match the
incoming \arg{Components0} correctly with the same number of slashes.

Consecutive slash-delimited compound terms decompose in Prolog as
nested slash-functors. Compound \verb$a/b/c$ decomposes to \verb$/(a/b, c)$
for example. Sub-term \verb$a/b$ decomposes to nested \verb$/(a, b)$. The
predicate converts any \verb$/(a, b/c)$ to \verb$/(a/b, c)$ so that the
shorthand flattens from \verb$a/(b/c)$ to \verb$a/b/c$.

Note that Prolog variables match partially-bound compounds; \verb$A$
matches \verb$A/(B/C)$. The first argument must therefore be fully ground
in order to avoid infinite recursion.

\begin{tags}
    \tag{To be done}
Enhance the predicate modes to allow variable components such
as A/B/C; mode (?, ?).
\end{tags}

    \predicate[semidet]{append_path}{3}{?Left, ?Right, ?LeftAndRight}
\arg{LeftAndRight} appends \arg{Left} path to \arg{Right} path. Paths in this context
amount to any slash-separated terms, including atoms and compounds.
Paths can include variables. Use this predicate to split or join
arbitrary paths. The solutions associate to the left by preference
and collate at \arg{Left}, even though the slash operator associates to
the right. Hence \verb$append_path(A, B/5, 1/2/3/4/5)$ gives one solution
of A = 1/2/3 and B = 4.

There is an implementation subtlety. Only find the \arg{Right} hand key if
the argument is really a compound, not just unifies with a slash
compound since Path/Component unifies with any unbound variable.
\end{description}

\chapter{library(swi/dicts): SWI-Prolog dictionary extensions}\label{sec:dicts}

This module provides extensions to the SWI-Prolog dictionary
implementation. It includes predicates for merging dictionaries,
putting values into dictionaries with custom merge behavior,
and handling dictionary members and leaves in a more flexible way.
It also includes predicates for creating dictionaries from lists
and converting dictionaries to compounds.

\subsection{Non-deterministic `dict_member(?Dict, ?Member)`}

This predicate offers an alternative approach to dictionary iteration in
Prolog. It makes a dictionary expose its leaves as a list exposes its
elements, one by one non-deterministically. It does not unify with
non-leaves, as for empty dictionaries.

\begin{code}
?- dict_member(a{b:c{d:e{f:g{h:i{j:999}}}}}, Key-Value).
Key = a^b/c^d/e^f/g^h/i^j,
Value = 999.

?- dict_member(Dict, a^b/c^d/e^f/g^h/i^j-999).
Dict = a{b:c{d:e{f:g{h:i{j:999}}}}}.
\end{code}

\vspace{0.7cm}

\begin{description}
    \predicate[det]{put_dict}{5}{+Key, +Dict0:dict, +OnNotEmpty:callable, +Value, -Dict:dict}
Updates dictionary pair calling for merge if not empty. Updates
\arg{Dict0} to \arg{Dict} with \arg{Key}-\arg{Value}, combining \arg{Value} with any existing
value by calling \arg{OnNotEmpty}/3. The callable can merge its first two
arguments in some way, or replace the first with the second, or even
reject the second.

The implementation puts \arg{Key} and \arg{Value} in \arg{Dict0}, unifying the result
at \arg{Dict}. However, if the dictionary \arg{Dict0} already contains another
value for the indicated \arg{Key} then it invokes \arg{OnNotEmpty} with the
original Value0 and the replacement \arg{Value}, finally putting the
combined or selected \arg{Value}_ in the dictionary for the \arg{Key}.

    \predicate[semidet]{merge_dict}{3}{+Dict0:dict, +Dict1:dict, -Dict:dict}
Merges multiple pairs from a dictionary \arg{Dict1}, into dictionary
\arg{Dict0}, unifying the results at \arg{Dict}. Iterates the pairs for the
\arg{Dict1} dictionary, using them to recursively update \arg{Dict0} key-by-key.
Discards the tag from \arg{Dict1}; \arg{Dict} carries the same tag as \arg{Dict0}.

Merges non-dictionaries according to type. Appends lists when the
value in a key-value pair has list type. Only replaces existing
values with incoming values when the leaf is not a dictionary, and
neither existing nor incoming is a list.

Note the argument order. The first argument specifies the base
dictionary starting point. The second argument merges into the
first. The resulting merge unifies at the third argument. The order
only matters if keys collide. Pairs from \arg{Dict1} replace key-matching
pairs in \arg{Dict0}.

Merging does not replace the original dictionary tag. This includes
an unbound tag. The tag of \arg{Dict0} remains unchanged after merge.

    \predicate[det]{merge_pair}{3}{+Dict0:dict, +Pair:pair, -Dict:dict}
Merges \arg{Pair} with dictionary. Merges a key-value \arg{Pair} into dictionary
\arg{Dict0}, unifying the results at \arg{Dict}.

Private predicate \verb$merge_dict_/3$
is the value merging predicate; given the original Value0 and the
incoming Value, it merges the two values at Value_.

    \predicate[semidet]{merge_dicts}{2}{+Dicts:list(dict), -Dict:dict}
Merges one or more dictionaries. You cannot merge an empty list of
dictionaries. Fails in such cases. It does \textbf{not} unify \arg{Dict} with a
tagless empty dictionary. The implementation merges two consecutive
dictionaries before tail recursion until eventually one remains.

Merging ignores tags.

    \predicate[nondet]{dict_member}{2}{?Dict:dict, ?Member}
Unifies with members of dictionary. Unifies \arg{Member} with all
dictionary members, where \arg{Member} is any non-dictionary leaf,
including list elements, or empty leaf dictionary.

Keys become tagged keys of the form \verb$Tag^Key$. The caret operator
neatly fits by operator precedence in-between the pair operator
(\verb$-$) and the sub-key slash delimiter (\verb$/$). Nested keys become
nested slash-functor binary compounds of the form
\verb$TaggedKeys/TaggedKey$. So for example, the compound \verb$Tag^Key-Value$
translates to Tag\{Key:Value\} in dictionary form. \verb$Tag^Key-Value$
decomposes term-wise as \verb$[-, Tag^Key, Value]$. Note that tagged
keys, including super-sub tagged keys, take precedence within the
term.

This is a non-standard approach to dictionary unification. It turns
nested sub-dictionary hierarchies into flatten pair-lists of
tagged-key paths and their leaf values.

    \predicate[semidet]{dict_leaf}{2}{-Dict, +Pair}
\nodescription
    \predicate[nondet]{dict_leaf}{2}{+Dict, -Pair}
Unifies \arg{Dict} with its leaf nodes non-deterministically. Each \arg{Pair} is
either an atom for root-level keys, or a compound for
nested-dictionary keys. \arg{Pair} thereby represents a nested key path
Leaf with its corresponding Value.

Fails for integer keys because integers cannot serve as functors.
Does not attempt to map integer keys to an atom, since this will
create a reverse conversion disambiguation issue. This \textbf{does} work
for nested integer leaf keys, e.g. \verb$a(1)$, provided that the integer
key does not translate to a functor.

\begin{arguments}
\arg{Dict} & is either a dictionary or a list of key-value pairs whose
syntax conforms to valid dictionary data. \\
\end{arguments}

    \predicate[nondet]{dict_pair}{2}{+Dict, -Pair}
\nodescription
    \predicate[det]{dict_pair}{2}{-Dict, +Pair}
Finds all dictionary pairs non-deterministically and recursively
where each pair is a Path-Value. Path is a slash-delimited
dictionary key path. Note, the search fails for dictionary leaves;
succeeds only for non-dictionaries. Fails therefore for empty
dictionaries or dictionaries of empty sub-dictionaries.

    \predicate[det]{findall_dict}{4}{?Tag, ?Template, :Goal, -Dicts:list(dict)}
Finds all dictionary-only solutions to \arg{Template} within \arg{Goal}. \arg{Tag}
selects which tags to select. What happens when \arg{Tag} is variable? In
such cases, unites with the first bound tag then all subsequent
matching tags.

    \predicate[semidet]{dict_tag}{2}{+Dict, ?Tag}
Tags \arg{Dict} with \arg{Tag} if currently untagged. Fails if already tagged
but not matching \arg{Tag}, just like \predref{is_dict}{2} with a ground tag. Never
mutates ground tags as a result. Additionally Tags all nested
sub-dictionaries using \arg{Tag} and the sub-key for the sub-dictionary.
An underscore delimiter concatenates the tag and key.

The implementation uses atomic concatenation to merge \arg{Tag} and the
dictionary sub-keys. Note that \predref{atomic_list_concat}{3} works for
non-atomic keys, including numbers and strings. Does not traverse
sub-lists. Ignores sub-dictionaries where a dictionary value is a
list containing dictionaries. Perhaps future versions will.

    \predicate[semidet]{create_dict}{3}{?Tag, +Dict0, -Dict}
Creates a dictionary just like \predref{dict_create}{3} does but with two
important differences. First, the argument order differs. \arg{Tag} comes
first to make \predref{maplist}{3} and \predref{convlist}{3} more convenient where the
Goal argument includes the \arg{Tag}. The new dictionary \arg{Dict} comes last
for the same reason. Secondly, always applies the given \arg{Tag} to the
new \arg{Dict}, even if the incoming Data supplies one.

Creating a dictionary using standard \predref{dict_create}{3} overrides the tag
argument from its Data dictionary, ignoring the \arg{Tag} if any. For
example, using \predref{dict_create}{3} for tag xyz and dictionary abc\Scurl{} gives
you abc\Scurl{} as the outgoing dictionary. This predicate reverses this
behaviour; the \arg{Tag} argument replaces any tag in a Data dictionary.

    \predicate[semidet]{is_key}{1}{+Key:any}
Succeeds for terms that can serve as keys within a dictionary.
Dictionary keys are atoms or tagged integers, otherwise known as
constant values. Integers include negatives.

\begin{arguments}
\arg{Key} & successfully unites for all dictionary-key conforming
terms: atomic or integral. \\
\end{arguments}

    \predicate[nondet]{dict_compound}{2}{+Dict:dict, ?Compound:compound}
Finds all compound-folded terms within \arg{Dict}. Unifies with all pairs
within \arg{Dict} as compounds of the form \verb$key(Value)$ where \const{key} matches
the dictionary key converted to one-two style and lower-case.

Unfolds lists and sub-dictionaries non-deterministically. For most
occasions, the non-deterministic unfolding of sub-lists results in
multiple non-deterministic solutions and typically has a plural
compound name. This is not a perfect solution for lists of results,
since the order of the solutions defines the relations between list
elements.

Dictionary keys can be atoms or integers. Converts integers to
compound names using integer-to-atom translation. However, compounds
for sub-dictionaries re-wrap the sub-compounds by inserting the
integer key as the prefix argument of a two or more arity compound.

    \predicate[semidet]{list_dict}{3}{?List, ?Tag, ?Dict}
\arg{List} to \arg{Dict} by zipping up items from \arg{List} with integer indexed keys
starting at 1. Finds only the first solution, even if multiple
solutions exist.
\end{description}

\chapter{library(swi/lists)}\label{sec:lists}

\begin{description}
    \predicate[semidet]{zip}{3}{?List1:list, ?List2:list, ?ListOfLists:list(list)}
Zips two lists, \arg{List1} and \arg{List2}, where each element from the first
list pairs with the same element from the second list. Alternatively
unzips one list of lists into two lists.

Only succeeds if the lists and sub-lists have matching lengths.

    \predicate[semidet]{pairs}{2}{?Items:list, ?Pairs:list(pair)}
\arg{Pairs} up list elements, or unpairs them in (-, +) mode. \arg{Pairs} are
First-Second terms where First and Second match two consecutive
\arg{Items}. Unifies a list with its paired list.

There needs to be an even number of list elements. This requirement
proceeds from the definition of pairing; it pairs the entire list
including the last. The predicate fails otherwise.

    \predicate[semidet]{indexed}{2}{?Items:list, ?Pairs:list(pair)}
\nodescription
    \predicate[semidet]{indexed}{3}{?List1:list, ?Index:integer, ?List2:list}
Unifies \arg{List1} of items with \arg{List2} of pairs where the first pair
element is an increasing integer index. \arg{Index} has some arbitrary
starting point, or defaults to 1 for one-based indexing. Unification
works in all modes.

    \predicate[semidet]{take_at_most}{3}{+Length:integer, +List0, -List}
\arg{List} takes at most \arg{Length} elements from \arg{List0}. \arg{List} for \arg{Length} of
zero is always an empty list, regardless of the incoming \arg{List0}. \arg{List}
is always empty for an empty \arg{List0}, regardless of \arg{Length}. Finally,
elements from \arg{List0} unify with \arg{List} until either \arg{Length} elements
have been seen, or until no more elements at \arg{List0} exist.

    \predicate[det]{select1}{3}{+Indices, +List0, -List}
Selects \arg{List} elements by index from \arg{List0}. Applies \predref{nth1}{3} to each
element of \arg{Indices}. The 1 suffix of the predicate name indicates
one-based \arg{Indices} used for selection. Mirrors \predref{select}{3} except that
the predicate picks elements from a list by index rather than by
element removal.

\begin{tags}
\mtag{See also}- \predref{nth1}{3} \\- \predref{select}{3}
\end{tags}

    \predicate[nondet]{select_apply1}{3}{+Indices, :Goal, +Extra}
Selects one-based index arguments from \arg{Extra} and applies these
extras to \arg{Goal}.

\begin{tags}
    \tag{See also}
\predref{apply}{2}
\end{tags}

    \predicate[nondet]{comb2}{2}{?List1, ?List2}
Unifies \arg{List2} with all combinations of \arg{List1}. The length of \arg{List2}
defines the number of elements in \arg{List1} to take at one time. It
follows that length of \arg{List1} must not be less than \arg{List2}. Fails
otherwise.

\begin{tags}
    \tag{See also}
\url{http://kti.ms.mff.cuni.cz/~bartak/prolog/combinatorics.html}
\end{tags}
\end{description}

\chapter{library(swi/memfilesio): I/O on Memory Files}\label{sec:memfilesio}

\begin{tags}
    \tag{author}
Roy Ratcliffe
\end{tags}

\section{Bytes and octets}

Both terms apply herein. Variable names reflect the subtle
but essential distinction. All octets are bytes but not all bytes are
octets. Byte is merely eight bits, nothing more implied, whereas octet
implies important inter-byte ordering according to some big- or
little-endian convention.\vspace{0.7cm}

\begin{description}
    \predicate[det]{with_output_to_memory_file}{3}{:Goal, +MemoryFile, +Options}
Opens \arg{MemoryFile} for writing. Calls \arg{Goal} using \predref{once}{1}, writing to
\verb$current_output$ collected in \arg{MemoryFile} according to the encoding
within \arg{Options}. Defaults to UTF-8 encoding.

    \predicate[det]{memory_file_bytes}{2}{?MemoryFile, ?Bytes:list}
Unifies \arg{MemoryFile} with \arg{Bytes}.

    \predicate[det]{put_bytes}{1}{+Bytes:list}
Puts zero or more \arg{Bytes} to current output.

A good reason exists for \textit{putting bytes} rather than writing codes.
The \predref{put_byte}{1} predicate throws with permission error when writing
to a text stream. \arg{Bytes} are \textbf{not} Unicode text; they have an
entirely different ontology.

\begin{tags}
    \tag{See also}
Character representation manual section
at \url{https://www.swi-prolog.org/pldoc/man?section=chars} for more
details about the difference between codes, characters and bytes.
\end{tags}

    \predicate[semidet]{same_memory_file}{2}{+MemoryFile1, +MemoryFile2}
Succeeds if, and only if, two memory files compare equal by
content. Comparison operates byte-by-byte and so ignores any
underlying encoding.
\end{description}

\chapter{library(swi/options)}\label{sec:options}

\begin{description}
    \predicate[det]{select_options}{4}{+Options, +RestOptions0, -RestOptions, +Defaults}
Applies multiple \predref{select_option}{4} predicate calls to a list of
\arg{Options}. Applies the list of \arg{Options} using a list of \arg{Defaults}.
Argument terms from \arg{Options} unify with \arg{RestOptions0}.

\arg{Defaults} are unbound if not present. The implementation selects an
option's Default from the given list of \arg{Defaults} using
\predref{select_option}{4}. Option terms must have one variable. This is
because \predref{select_option}{4}'s fourth argument is a single argument. It
never unifies with multiple variables even though it succeeds, e.g.
\verb$select_option(a(A, B), [], Rest, 1)$ unifies A with 1, leaving B
unbound.

There is a naming issue. What to call the incoming list of Option
arguments and the \arg{Options} argument with which the Option terms
unify? One possibility: name the \arg{Options} argument \arg{RestOptions0} since
they represent the initial set of \arg{RestOptions} from which \arg{Options}
select. This clashes with \predref{select_option}{4}'s naming convention since
\arg{Options} is the argument name for \arg{RestOptions0}'s role in the
option-selection process. Nevertheless, this version follows this
renamed argument convention.

The predicate is useful for selecting options from a list of
options, especially when the options are not known in advance or
when they need to be filtered based on certain criteria.

Example:

\begin{code}
?- select_options([a(A), b(B)], [a(1), b(2), c(3)], Rest, [a(0), b(0)]).
Rest = [c(3)],
A = 1,
B = 2.
\end{code}

\begin{arguments}
\arg{Options} & The list of options to select from. \\
\arg{RestOptions0} & The initial list of remaining options. \\
\arg{RestOptions} & The remaining options after selection. \\
\arg{Defaults} & The list of default values for options. \\
\end{arguments}
\end{description}

\chapter{library(swi/paxos)}\label{sec:paxos}

\begin{description}
    \predicate[semidet]{paxos_quorum_nodes}{1}{-Nodes:list(nonneg)}
\arg{Nodes} is a list of Paxos consensus nodes who are members of the
quorum. Fails if Paxos not yet initialised.

\begin{arguments}
\arg{Nodes} & is a list of node indices in low-to-high order. \\
\end{arguments}

    \predicate[semidet]{paxos_quorum_nth1}{1}{?Nth1:nonneg}
Unifies \arg{Nth1} with the \textit{order} of this node within the quorum.
Answers 1 if this node comes first in the known quorum of
consensus nodes, for example.
\end{description}

\chapter{library(swi/pengines)}\label{sec:pengines}

\begin{description}
    \predicate[det]{pengine_collect}{2}{-Results, +Options}
\nodescription
    \predicate[det]{pengine_collect}{4}{?Template, +Goal, -Results, +Options}
Collects Prolog engine results. Repackages the collect predicate
used by the Prolog engine tests. There is only one minor difference.
The number of replies maps to \predref{replies}{1} in \arg{Options}. Succeeds if not
provided but unites with the integer number of replies from all
engines whenever passed to \arg{Options}. \arg{Options} partitions into three
sub-sets: next options, state options and ask options.

The implementation utilises a mutable state dictionary to pass
event-loop arguments and accumulate results. So quite useful. Note
also that the second \arg{Goal} argument is \textbf{not} module sensitive. There
consequently is no meta-predicate declaration for it.

The arity-2 form of pengine_collect expects that the pengine_create
options have asked a query. Otherwise the collect waits indefinitely
for the engines to stop.

It is possible that the engine could exit \textbf{before} the collector
asks for results. Prolog engines operate asynchronously. The collect
handler pre-empts failure and avoids an ask-triggered exception by
only asking existing engines for results. This does not eliminate
the possibility entirely. It only narrows the window of opportunity
to the interval in-between checking for existence and asking.

\begin{arguments}
\arg{Results} & are the result terms, a list of successful \arg{Goal} results
accumulated by appending results from all the running engines. \\
\end{arguments}

    \predicate[semidet]{pengine_wait}{1}{Options}
Waits for Prolog engines to die. It takes time to die. If alive,
wait for the engines by sampling the current engine and child
engines periodically. \arg{Options} allows you to override the default
number of retries (10) and the default number of retry delays (10
milliseconds). Fails if times out while waiting for engines to die;
failure means that engines remain alive (else something when wrong).

The implementation makes internal assumptions about the pengines
module. It accesses the dynamic and volatile predicates
\predref{current_pengine}{6} and \predref{child}{2}. The latter is thread local.
\end{description}

\chapter{library(swi/settings)}\label{sec:settings}

\begin{description}
    \predicate[semidet]{local_settings_file}{1}{-LocalFile:atom}
Breaks the module interface by asking for the current local settings
file from the settings module. The \predref{local_file}{1} dynamic predicate
retains the path of the current local file based on loading. Loading
a new settings file using \predref{load_settings}{1} pushes a \textbf{new} local
file without replacing the old one, so that the next \predref{save_settings}{0}
keeps saving to the original file.

\begin{arguments}
\arg{LocalFile} & is the absolute path of the local settings file to be
utilised by the next \predref{save_settings}{1} predicate call. \\
\end{arguments}

    \predicate[semidet]{setting}{3}{:Name, ?Value, :Goal}
Semi-deterministic version of \predref{setting}{2}. Succeeds only if \arg{Value}
succeeds for \arg{Goal}; fails otherwise. Calls \arg{Goal} with \arg{Value}.

Take the following example where you only want the setting
predicate to succeed when it does \textit{not} match the empty atom.

\begin{code}
setting(http:public_host, A, \==(''))
\end{code}

\end{description}

\chapter{library(swi/streams)}\label{sec:streams}

\begin{description}
    \predicate[det]{close_streams}{2}{+Streams:list, -Catchers:list}
Closes zero or more \arg{Streams} while accumulating any exceptions at
\arg{Catchers}.
\end{description}

\chapter{library(swi/zip)}\label{sec:zip}

\begin{description}
    \predicate[nondet]{zip_file_info}{4}{+File, -Name, -Attrs, -Zipper}
Non-deterministically walks through the members of a zip \arg{File},
moving the \arg{Zipper} current member. It does \textit{not} read the contents of
the zip members, by design. You can use the \arg{Name} argument to select
a member or members before reading.

\begin{arguments}
\arg{Zipper} & unifies with the open \arg{Zipper} for reading using
\predref{zipper_codes}{3} or \predref{zipper_open_current}{3}. \\
\end{arguments}

    \predicate[semidet]{zipper_codes}{3}{+Zipper, -Codes, +Options}
Reads the current \arg{Zipper} file as \arg{Codes}. \arg{Options} may be:

\begin{shortlist}
    \item \verb$encoding(utf8)$ for UTF-8 encoded text, or
    \item \verb$type(binary)$ for binary octets, and so on.
\end{shortlist}
\end{description}

\chapter{library(with/output)}\label{sec:output}

\begin{description}
    \predicate[semidet]{with_output_to}{3}{+FileType, ?Spec, :Goal}
Runs \arg{Goal} with \verb$current_output$ pointing at a file with UTF-8
encoding. In (+, -, :) mode, creates a randomly-generated file with
random new name unified at \arg{Spec}. With \arg{Spec} unbound, generates a
random one-time name. Does \textbf{not} try to back-track in order to
create a unique random name. Hence overwrites any existing file.

This is an arity-three version of \predref{with_output_to}{2}; same name,
different arity. Writes the results of running \arg{Goal} to some file
given by \arg{Spec} and \arg{FileType}. Fails if \arg{Spec} and \arg{FileType} fail to
specify a writable file location.

When \arg{Spec} unbound, generates a random name. Binds the name to \arg{Spec}.

    \predicate[semidet]{with_output_to_pl}{2}{?Spec, :Goal}
Runs \arg{Goal} with \verb$current_output$ pointing at a randomly-generated
Prolog source file with UTF-8 encoding. In (+, :) mode, creates a
Prolog file with name given by \arg{Spec}.
\end{description}

