Documenting Unison Code

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.

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, as in x = {{my docs}}. We'll use a simple example for the basics:

{{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:

.> 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.

.> 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:

.> 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"
    ```
}}
.> 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.

.> 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 FormattingDocs Syntax
italicized*asterisks* or _single underscore_
bold__double underscore__ or **double asterisk**
strikethrough~~double tilde~~
monospacetwo single quotes
bullet list*
numbered list1. 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")]))) }}

Linking to both external URLs and definitions in your codebase can be done in several ways:

Link typeDocs SyntaxPurpose
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 linkLinks 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

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 the Jabberwock.whiffle.doc namespace. I.e. a document called Jabberwock.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 and Jabberwock.whiffle.doc.examples.ex2.

We hope you enjoy writing documentation in Unison! More details on Unison documentation can be found in a transcript describing the full feature set. 😃