This is the top-level module for the graphviz library. It provides
functions to convert Graphs into the
Dot language used by the Graphviz suite of programs (as well as
a limited ability to perform the reverse operation).

Apart from not having to pass multiple values around, another
advantage of using GraphvizParams over the previous approach is that
there is no distinction between clustering and non-clustering variants
of the same functions.

A value of type GraphvizParams n nl el cl l indicates that
the Graph has a node type of n, node labels of type nl,
edge labels of type el, corresponding clusters of type cl and
after clustering the nodes have a label of type l (which may or
may not be the same as nl).

The tuples ins the function types represent labelled nodes (for
(n,nl) and (n,l)) and labelled edges ((n,n,el); the value
(f,t,ftl) is an edge from f to l with a label of ftl).

A default GraphvizParams value which assumes the graph is
directed, contains no clusters and has no Attributes set.

If you wish to have the labels of the nodes to have a different
type after applying clusterBy from before clustering, then you
will have to specify your own GraphvizParams value from
scratch (or use blankParams).

If you use a custom clusterBy function (which if you actually
want clusters you should) then you should also override the
(nonsensical) default clusterID.

A variant of defaultParams that enforces that the clustering
type is '()' (i.e.: no clustering); this avoids problems when
using defaultParams internally within a function without any
constraint on what the clustering type is.

A GraphvizParams value where every field is set to
undefined. This is useful when you have a function that will
set some of the values for you (e.g. setDirectedness) but you
don't want to bother thinking of default values to set in the
meantime. This is especially useful when you are
programmatically setting the clustering function (and as such do
not know what the types might be).

Pseudo-inverse conversion.

A pseudo-inverse to graphToDot; "pseudo" in the sense that
the original node and edge labels aren't able to be
reconstructed.

Graph augmentation.

The following functions provide support for passing a Graph
through the appropriate GraphvizCommand to augment the Graph by
adding positional information, etc.

A CustomAttribute is used to distinguish multiple edges between
two nodes from each other.

Note that the reason that most of these functions do not have
unsafePerformIO applied to them is because if you set a global
Attribute of:

Start (StartStyleRandomStyle)

then it will not necessarily be referentially transparent (ideally,
no matter what the seed is, it will still eventually be drawn to the
same optimum, but this can't be guaranteed). As such, if you are sure
that you're not using such an Attribute, then you should be able to
use unsafePerformIO directly in your own code.

Manual augmentation.

This section allows you to manually augment graphs by providing
fine-grained control over the augmentation process (the standard
augmentation functions compose these together). Possible reasons for
manual augmentation are:

Note that whilst these functions provide you with more control, you
must be careful how you use them: if you use the wrong DotRepr for
a Graph, then the behaviour of augmentGraph (and all functions
that use it) is undefined. The main point is to make sure that the
defined DotNode and DotEdge values aren't removed (or their ID
values - or the Attributes for the DotEdges - altered) to
ensure that it is possible to match up the nodes and edges in the
Graph with those in the DotRepr.

Use the Attributes in the provided DotGraph to augment the
node and edge labels in the provided Graph. The unique
identifiers on the edges are also stripped off.

Please note that the behaviour for this function is undefined if
the DotGraph does not come from the original Graph (either
by using a conversion function or by passing the result of a
conversion function through a GraphvizCommand via the
DotOutput or similar).