Unison comes with a powerful documentation format which makes it easy to write rich, correct documentation. In addition to basic Markdown-like syntax and formatting, Unison documentation also supports inline evaluation, typechecked code snippets, and embedding docs within other docs. We'll walk through these features below.
The basics
Documentation blocks start with {{
and end with a matching }}
. This syntax creates an expression of type Doc
and it can be used anywhere in your code where an expression can be written.
aDocDefinition : Doc
aDocDefinition = {{This is a simple documentation block.}}
Anonymous documentation blocks are blocks that are created immediately before the definitions in your code. This means we don't need to assign our documentation block to a value; instead, the doc is automatically created with the same name as the definition, followed by doc
:
{{Maya Angelou was an acclaimed poet, director, essayist, and novelist.}}
poet = "Maya Angelou"
In the UCM we should see:
⍟ These new definitions are ok to `add`:
poet.doc : Doc
poet : Text
Here our anonymous doc is automatically linked to poet
as the term poet.doc
.
To read a term's documentation, use the docs
command in the UCM like this:
scratch/main> docs poet
Maya Angelou is an acclaimed poet, director, essayist, and novelist.
A UCM command taking the form docs myTermName
will look for a term called myTermName.doc
in the file or codebase, so we do not need to explicitly link our docs to our code if we respect that naming convention.
To recap the basics:
- Start a documentation block with
{{ double curly braces }}
- Anonymous docs link a definition to its documentation and are placed immediately above a definition
- Read the docs in the UCM using the
docs
command followed by a definition name
Evaluating and including code
Let's write some documentation which demonstrates how Unison can evaluate code.
{{
``repeat n text`` is a function which will
repeat the provided text a specified number of times.
}}
repeat : Nat -> Text -> Text
repeat n text =
go i acc =
use Nat >=
if i >= n then acc
else
use Nat +
use Text ++
go (i + 1) (text ++ acc)
go 0 ""
We've introduced a new Unison documentation feature with the double backtick syntax. Double backticks are how we include inlined snippets of Unison code. These snippets are typechecked, so you know the code in your documentation is going to accurately represent your codebase. If we were to rename repeat
to echo
the docs would reflect that automatically.
Unison docs also support evaluating entire blocks of code. This can be useful for specifying longer examples and use cases. Let's add one to our repeat
documentation block:
{{
''repeat'' is a function which will repeat the provided text a specified number of times.
Examples:
```
(repeat 2 "rose is a ") ++ "rose"
```
}}
Note, the blank line after "Examples:" and before the code block is important, otherwise the example may not render properly.
The documentation will render both the source code and the result of evaluating the code for anything between triple backticks.
scratch/main> docs repeat
`repeat` is a function which will repeat the provided text a specified number of times.
Examples:
repeat 2 "rose is a " Text.++ "rose"
⧨
"rose is a rose is a rose"
Let's imagine our docs would really benefit from displaying the full source code of the function they're describing. We can do that with the @source{myTerm}
syntax.
{{
`repeat` is a function which will repeat the provided text a specified number of times.
Source:
@source{repeat}
Examples:
```
(repeat 2 "rose is a ") ++ "rose"
```
}}
The full implementation of repeat
is now on display:
scratch/main> docs repeat
`repeat` is a function which will repeat the provided text a specified number of times.
Source:
repeat n text =
go i acc =
if i >= n then acc
else
use Nat +
use Text ++
go (i + 1) (text ++ acc)
go 0 ""
Examples:
repeat 2 "rose is a " Text.++ "rose"
⧨
"rose is a rose is a rose"
Maybe our documentation is better served by just including the signature of a function. Let's try that with @signature{myTerm}
:
{{
@signature{repeat}
`repeat` is a function which will repeat the provided text a specified number of times.
Examples:
```
(repeat 2 "rose is a ") ++ "rose"
```
}}
scratch/main> docs repeat
repeat : Nat -> Text -> Text
`repeat` is a function which will repeat the provided text a specified number of times.
Examples:
repeat 2 "rose is a " Text.++ "rose"
⧨
"rose is a rose is a rose"
We used @signature{myTerm}
to include the signature on its own separate line, but we needed to inline it in a doc, we can use @inlineSignature{myTerm}
instead.
It's common for Unison docs to be composed of smaller components. We can combine Doc
values using the {{ subdoc }}
syntax. In our repeat.doc
code we might extract the "Examples" portion of our documentation into a separate term if it grows too long.
{{
@signature{repeat}
`repeat` is a function which will repeat the provided text a specified number of times.
{{ repeat.doc.examples }}
}}
repeat.doc.examples : Doc
repeat.doc.examples = {{
Examples:
```
(repeat 2 "rose is a ") ++ "rose"
```
```
repeat 0 "zero"
```
}}
When we want to read the docs for repeat
, the entire docs block will be rendered to the user.
scratch/main> docs repeat
`repeat : Nat -> Text -> Text`
`repeat` is a function which will repeat the provided text a specified number of times.
Examples:
repeat 2 "rose is a " Text.++ "rose"
⧨
"rose is a rose is a rose"
repeat 0 "zero"
⧨
""
To summarize, Unison docs can execute and embed code in the following ways:
``double backticks``
are used to inline Unison code```triple backticks```
wrap executable code blocks@source{myTerm}
is used for displaying the source code@signature{myTerm}
includes a signature in the docs@inlineSignature{myTerm}
includes a signature with inline styling in a doc block{{ subdoc }}
will display another doc's content within the enclosing doc
Basic text formatting cheat sheet
Unison supports the following text formatting features:
Text Formatting | Docs Syntax |
italicized | *asterisks* or _single underscore_ |
bold | __double underscore__ or **double asterisk** |
strikethrough | ~~double tilde~~ |
monospace | two single quotes |
bullet list | * |
numbered list | 1. My List |
heading | # Heading |
image | {{ Doc.Image {{ some alt text }} {{ http://img.com }} (Some {{ A caption }}) }} |
video | {{ Special (Embed (Any (Video [(MediaSource "test.mp4" None)] [("poster", "test.png")]))) }} |
Link syntax cheat sheet
Linking to both external URLs and definitions in your codebase can be done in several ways:
Link type | Docs Syntax | Purpose |
external url | [An external url](https://unison-lang.org) | Links to an external URL, used for including relevant resources |
term/type link | {Some} is a term link and {type Optional} is a type link | Links to a term or type in the codebase, documentation UI's like the one on unison share may enable click-through linking |
named term/type link | [a named term link]({Some}) and [A named type link]({type Optional}) | Links to a term or type in the codebase but gives the link the name in square brackets for readability |
Tables in documents
Unison docs can also include tables to organize information.
Inside a doc block elment, start a table with the {{ docTable }}
syntax and then provide a nested list of doc elements. The first row of the list will be used as the table's header. Subsequent rows will be used as the table's body. There is currently no way to skip or merge cells in a table, so the number of cells in a row should not change.
{{ docTable
[
[{{ Header 1 }}, {{ Header 2 }}],
[{{ row1 }}, {{ row2 }}]
]
}}
Diagrams in documents
Unison docs are capable of rendering mermaid diagrams in fenced codeblock elements. Mermaid enables you to write markdown-like syntax to generate diagram types like flowcharts, state diagrams, and sequence diagrams. Inside a doc element, open up a fenced codeblock with the triple backtick syntax followed by "mermaid" as the language type, ``` mermaid
. This will tell the Unison doc renderer that the next bit of code should be treated as a drawing.
The following mermaid fenced codeblock will render the diagram below:
_mermaid1 : Doc
_mermaid1 =
{{
``` mermaid
sequenceDiagram
Note left of Client: Sends SYN
Client->>Server: SYN
Note right of Server: Receives SYN
Note right of Server: Sends SYN + ACK
Server->>Client: SYN + ACK
Note left of Client: Receives SYN + ACK
Note left of Client: Sends ACK
Client->>Server: ACK
Note right of Server: Receives ACK
```
}}
sequenceDiagram
Note left of Client: Sends SYN
Client->>Server: SYN
Note right of Server: Receives SYN
Note right of Server: Sends SYN + ACK
Server->>Client: SYN + ACK
Note left of Client: Receives SYN + ACK
Note left of Client: Sends ACK
Client->>Server: ACK
Note right of Server: Receives ACK
LaTeX in documents
Fenced codeblocks can also be used to render LaTeX. The triple backtick syntax followed by "latex" as the language type, ``` latex
, will tell the Unison doc renderer that the next bit of code should be treated as LaTeX.
f(\relax{x}) = \int_{-\infty}^\infty
\hat{f}(\xi)\,e^{2 \pi i \xi x}
\,d\xi
Suggested documentation conventions
Although documentation values don't require any particular structure you might try writing your docs according to a few guidelines:
- Start with a brief one sentence or short paragraph overview, then optionally include a longer description, include some examples which illustrate common cases and edge cases, and finally link to related definitions and further reading.
- Follow sensible naming conventions for documentation and examples. For a definition
Jabberwock.whiffle
, for example: - Its primary documentation should be called
Jabberwock.whiffle.doc
, and secondary docs could be in theJabberwock.whiffle.doc
namespace. I.e. a document calledJabberwock.whiffle.doc.advancedUsages
could show advanced usages of the term. - Non-inlined documentation examples could be in the
Jabberwock.whiffle.doc.examples
namespace. For instance:Jabberwock.whiffle.doc.examples.ex1
andJabberwock.whiffle.doc.examples.ex2
.
- Its primary documentation should be called
- Follow sensible naming conventions for documentation and examples. For a definition
We hope you enjoy writing documentation in Unison! More details on Unison documentation can be found in a transcript describing the full feature set. 😃