Racket: Scriblling In-Source Documentation

Written by Dominik Joe Pantůček on January 16, 2020.

Modern systems have become increasingly complex since the beginning of the computing revolution. As these systems are programmed by humans, it is really easy to create systems with erroneous behavior. A well-documented code lowers the risks of introducing bugs in the programs – which should be something to always aim to. Read on to see how we here at Trustica approach this problem.

A well-designed software consists of well-defined modules which behave according to their specification. But what is this specification? In Racket[1] we use contracts[2] to specify the behavior of all functions module provides[3]. As useful as contracts are for specifying the inputs and the outputs of a function, the cannot – alone – provide a comprehensive picture of what a module full of functions provides and how it should work.

This is where Racket’s documentation language, Scribble[4], comes to play. Writing documentation in Scribble is pretty straightforward and if you ever used Markdown[5] or LaTeX[6], you should immediately feel at home with it. We will not focus on the actual Scribble language here (that might be a good idea for a future post) but rather we will look at how it can be embedded into the source code so that the documentation is close to the documented features.

From the programmer perspective, the in-source documentation capability is just another module that is required[7] into the program. This module scribble/srcdoc[8] gives new provide forms, such as:

  • proc-doc
  • proc-doc/names
  • thing-doc
  • form-doc

It also provides a new require form for-doc, which allows for importing any Racket module to be used for writing the documentation. Yes, the in-source documentation can be scripted! Now with all of this, there is only one syntactic piece missing – a reader that gives us the possibility of combining the S-expression based code with more prose-like documentation. And that is the addition to the language syntax, called at-exp language.

Although it might seem a bit complex at first glance, the actual code to start writing a decent in source documentation is just this:

#lang at-exp racket
(require scribble/srcdoc
         (for-doc scribble/manual))

The scribble/manual module provides some neat forms for referencing, headings, lists and other “standard” features of any text markup language.

Syntactically the at-exp reader uses the “at”-character “@” to escape into the at-exp syntax. These two are syntactically equivalent:

(displayln "Hello")
@displayln{Hello}

And of course, there are rules for escaping the escape and therefore you can nest standard S-expressions with @-expressions indefinitely. So syntactically we are done here. Now how do we glue this with the contracts and what does it produce?

Turns out this is the easiest part. All the aforementioned documentation provide forms do this for you. Let’s take our favorite function and document it:

(provide
 (proc-doc/names
  list-sum
  (-> (listof number?) number? number? number?)
  (lst a b)
  @{

    Sums two elements of given list of numbers.

    }))

(define (list-sum lst a b)
  (+ (list-ref lst a)
     (list-ref lst b)))

 

And that is all. Isn’t it cool? Do not forget to check out an example in the futures-sort[9] package. The documentation source[10] and resulting HTML renderings[11] are available there!

 

See you next week with some – dare I say – exciting news!


References

1. https://racket-lang.org/

2. https://trustica.cz/en/2020/01/02/racket-contract-based-programming/

3. https://docs.racket-lang.org/guide/module-provide.html

4. https://docs.racket-lang.org/scribble/index.html

5. Wikipedia contributors. (2019, December 24). Markdown. In Wikipedia, The Free Encyclopedia. Retrieved 15:05, January 16, 2020, from https://en.wikipedia.org/w/index.php?title=Markdown&oldid=932190046

6. https://www.latex-project.org/

7. https://docs.racket-lang.org/guide/module-require.html

8. https://docs.racket-lang.org/scribble/srcdoc.html

9. https://pkgs.racket-lang.org/package/futures-sort

10. https://github.com/dzoep/futures-sort/blob/master/main.rkt#L25

11. https://docs.racket-lang.org/futures-sort/index.html