#lang scribble/doc
@(require "common.ss" (prefix-in c: "collatz-doc.ss") scribble/core)
@title[#:tag "literate"]{Literate Programming}
The techniques used for in-source documentation extend to the creation
of WEB-like literate programming tools. @Figure-ref["Collatz"] shows
an example use of our literate-programming library; the left-hand side
shows a screenshot of DrScheme editing the source code for a short,
literate discussion of the Collatz conjecture, while the right-hand
side shows the rendered output.
Literate programs written with our library look like ordinary Scribble
documents, except that they start with @code-elem|{#lang scribble/lp}|
and use @scheme[chunk] to introduce a piece of the implementation. A
use of @scheme[chunk] consists of a name followed by definitions
and/or expressions:
@;
@code-block|{
@chunk[
... definitions ...
... expressions ...]
}|
@;
The definitions and expressions in a chunk can refer to other chunks
by their names.
Unlike a normal Scribble program, running a
@schememodname[scribble/lp] program ignores the prose exposition and
instead evaluates the program in the chunks. In literate programming
terminology, this process is called @defterm{tangling} the program.
Thus, to a client module, a literate program behaves just like its
illiterate variant. The compiled form of a literate program
does not contain any of the documentation, nor does it depend on the
runtime support for Scribble, just as if an extra-linguistic tangler
had been used. Consequently, the literate implementation suffers no
overhead due to the prose.
To recover the prose, the
@;
@code-block|{@lp-include[_filename]}|
@;
form extracts a literate view of the program from
@scheme[_filename]. In literate programming terminology, this process
is called @defterm{weaving} the program. The right-hand side of
@Figure-ref["Collatz"] shows the woven version of the code in the
screenshot.
Both weaving and tangling with @schememodname[scribble/lp] work at the
level of syntactic extensions, and not in terms of manipulating source
text. As a result, the language for writing prose is extensible, because
Scribble libraries such as @schememodname[scribble/manual] can be
imported into the document. The language for implementing the program
is also obviously extensible, because a chunk can include imports from other PLT
Scheme libraries. Finally, even the bridge between the prose and the
implementation is extensible, because the document author can create
new syntactic forms that expand to a mixture of prose, implementation,
and uses of @scheme[chunk].
Tangling via syntactic extension also enables many tools for
Scheme programs to automatically apply to literate Scheme
programs. The arrows in @Figure-ref["Collatz"]'s screenshot demonstrate how
DrScheme can draw arrows from chunk bindings to chunk references, and
from the binding occurrence of an identifier
to its bound occurrences, even across chunks.
These latter arrows are particularly helpful with
literate programs, where lexical scope is sometimes obscured by the
way that textually disparate fragments of a program are eventually
tangled into the same scope. DrScheme's interactive REPL, test-case
coverage support, module browser, executable generation, and other tools also
work on literate programs.
To gain some experience with non-trivial literate programming in
Scribble, we have written a 34-page literate program that describes
our implementation of the Chat Noir game, which is distributed with
PLT Scheme. The source is included in the distribution as
@filepath{chat-noir-literate.ss}, and the rendered output is in the
help system and online at
@show-link{http://docs.plt-scheme.org/games/chat-noir.html}.
@(figure**
"Collatz"
"Literate programming example"
(make-table
(make-style #f
(list
; custom cell styles to improve output:
(make-table-cells (list (list (make-style "Half" null)
(make-style "Half" null))))))
(list
(list (make-paragraph plain (list (image #:scale .6 "collatz.png")))
(lp-minipage (make-splice (part-blocks c:doc)))))))