Document Weaver

Literate Programming quergedacht

Dr. Meik Teßmer

2025-10-01

1 docweaver

docweaver includes files and file parts to generate a neweb compatible literate program. From there the usual tooling applies.

Example pipeline for a single document source file and multiple source code files:

file.dw --> docweaver --> file.nw --> neweave --> file.md --> pandoc --> PDF
            ^   ^                                               |
            |   |                                               +------> HTML
code.py ----+   |
                |
more_code.go ---+

A file can be included literally, helpful for Markdown files:

<<!path_to_file>>

To include a code chunk:

<<path_to_file:name of code chunk>>= (go)

If a code chunks appears multiple times in a code file, a number can be used to select a specific one:

<<path_to_file:name of code chunk#2>>= (go)

~ will be expanded to the home directory; relative paths are possible.

To mark a code chunk, use the comment characters of the programming language and add a code chunk definition; close the code chunk with @:

    #<<define filter>>=
    def a_filter():
        pass

    #@

This code chunk can then be referenced by

<<path_to_file:define filter>>= (python)

2 Schwierigkeiten des klassischen Literate Programming

Ausgangspunkt: (Knuth 1984) + How to read

blockdiag {
  WEB -> TEX [label="weave"];
  WEB -> PASCAL [label="tangle"];
  PASCAL -> Programm [label="Compiler"];
  TEX -> DVI [label="LaTeX"];
}

Warum eignet sich WEB wie auch noweb und neweb nicht?

3 Bisher geleistete Vorarbeit

klass. LP: kleine Einheiten (Module aka Sections), bestehend aus documentation, definitions, code → inspiriert von Pierre-Arnoul de Marneffe: Holon programming

The “Holon” concept has been introduced in biological and behavior sciences by Koestler. This concept proceeds from the work of Simon. It is used for instance to analyze complex living organisms or complex social systems. This neologism is from Greek “holos”, i.e., whole, and the suffix “-on” meaning “part”. A holon is a “part of a whole”. The reader is forewarned to not mix up the holon concept with the “module” one.

“Hierarchy”: Each holon is composed by other holons which are “refinements” of the former holon. These holons are submitted to some rigid rules; they perform the “detail” operations which, put together, compose the function of the former holon.

“Tendency to Integration”: The holon integrates with other holons in the hierarchy according to a flexible strategy. This integration must be understood as a will to close cooperation with the other holons for the emergence of a “tougher” and more efficient component.

(Marneffe 1973, pp. 8-9)

Grundidee ist im Wesentlichen top-down; trägt dieser Ansatz noch immer, insbesondere bei OO? Gerade exploratives Entwickeln funktioniert eher anders.

Eludicative Programming ist da näher… Sie erschlagen die Trennung mit einem Side-by-Side-Betrachter. Das ist allerdings ein anderer Ansatz: Hier geht es um ein Programmierparadigma, nicht um die Darstellung von Code. Das Paradigma führt zu einer anderen Herangehensweise bei der Entwicklung: Erst denken, Gedanken in Textform niederlegen (1. Stufe der Korrektur), Text in Code-Form überführen (2. Stufe der Korrektur).

Einzig die Frage der Organisation des Codes bleibt offen:

Daran schließt sich direkt die Frage nach dem Kommunikationsmedium an:

Wie erfolgreich ein Medium beim Leser ist, hängt zu einen Gutteil von dessen Vorerfahrung ab. Dieser Umstand bietet einen möglichen Ansatzpunkt:

  1. Der Anfänger ist (zumindest heute noch) schriftlich geprägt durch lineare Inhalte. Erst schleppend werden diese ergänzt, aber wir sind noch weit entfernt von Alan Kays Vision des Dynabooks[link] bzw. Neal Stephensons Fibel aus Diamond Age[link]. Für diese Lesergruppe bietet sich eine klassische Abfolge an:

    1. Allgemeine Einführung
    2. Vision
    3. Hauptkomponenten
    4. Aufteilung dieser in Teilkomponenten und deren weitere Verfeinerung in Folgeabschnitten

    Dies entspricht dem top-down-Ansatz, der vom klassischen LP genutzt wird.

  2. Der erfahrene Entwickler nutzt Programme/Dokumentation für:

    Er benötigt einen möglichst schnellen und zielgerichteten Zugriff und hat kein Interesse an Einführungen.

4 Alternativer Ansatz

Welche Möglichkeiten gibt es, beiden Anforderungen gerecht zu werden? Eine Idee: Code und Dokumentation werden Seite an Seite entwickelt, aber nicht in derselben Datei. Damit unterscheidet sich dieser Ansatz von Knuths Literate Programming, nutzt aber den Gedanken der Inklusion von Code in die Dokumentation, in dem Code-Teile in die Dokumentation eingeblendet werden. Als Ergebnis erhält man eine LP-konforme Datei, die wiederum mit neweave ins Markdown-Format und mit pandoc in beliebige Zielformate konvertiert werden kann. Der Verarbeitungsablauf für docweaver sieht somit wie abgebildet.

blockdiag {
  ".dw-Datei" -> ".nw-Datei" [label="weaver"];
  ".nw-Datei" -> ".md-Datei" [label="neweb"];
  ".nw-Datei" -> "Code-Datei" [label="newtangle"];
  ".md-Datei" -> ".html", ".pdf", "..." [label="pandoc"];
}

Wie werden nun Code-Abschnitte bezeichnet? Im klassischen LP-Ansatz besteht diese Notwendigkeit nicht, aber wenn bestimmte Code-Abschnitte eingebunden werden sollen, müssen sie a) benannt und b) in ihrem Umfang definiert werden. Eine Möglichkeit ist, die Kommentarfähigkeit der jeweiligen Programmiersprache zu nutzen und dort die benötigten Angaben zu hinterlegen. Ein Beispiel für die Definition eines Bereichs:

    #<<Filter definieren>>=
    def ein_filter():
        pass

    #@

Normalerweise ist es kein Problem, an einer beliebigen Stelle eine Kommentarzeile einzufügen. Die Einbindung erfolgt unter Angabe der Quelle-Datei, gefolgt von einem Doppelpunkt und dem Bereichsnamen sowie der fortlaufenden Nummer (gezählt wird ab 0). Damit ist es möglich, wie im klassischen LP auch zusammenhängende Code-Abschnitte umzusetzen:


    Folgende Funktion definiert einen Filter:



    Weiter geht ...

Die folgende Zeile fügt den zweiteiligen Code Chunk Hauptfunktion aus der Datei weaver.py ein:

0 ⟨Hauptfunktion⟩≡ 1 ▷

if __name__ == "__main__":
    main()

1 ⟨Hauptfunktion⟩≡ ◁ 0 2 ▷

print()

Eine Schwierigkeit ist festzustellen, welche Kommentarzeichen relevant sind. Die Sprachangabe am Ende der Einbindungszeile hilft dabei, die richtigen Zeichen für die jeweilige Sprache zu wählen. docweaver ergänzt in der .nw-Datei für jeden Code-Chunk die notwendigen Sprach-Hinweise, so dass anschließend ein passendes Syntax Highlighting möglich ist.

5 Tests

5.1 C

2 ⟨Hauptfunktion⟩≡ ◁ 1 3 ▷

int main(void)
{
    printf("Hello World!\n");

    return 0;
}

5.2 C++

3 ⟨Hauptfunktion⟩≡ ◁ 2 5 ▷

int main()
{
    std::cout << "Hallo Welt!\n";
}

5.3 Java

4 ⟨Hauptmethode⟩≡

public class HalloWelt {
    public static void main(String[] args) {
        System.out.println("Hallo Welt!");
    }
}

5.4 Go

5 ⟨Hauptfunktion⟩≡ ◁ 3

func main() {
    fmt.Println("Hallo Welt!")
}

6 Ausblick


6 ⟨build-script⟩≡

#!/bin/sh

if [ -z "${NOWEB_CODE}" ]; then
        NOWEB_CODE=`pwd`/code
fi

[ -d "${NOWEB_CODE}" ] || mkdir -p "${NOWEB_CODE}"

FILES=""

for f in ${FILES}; do
        newtangle -R "$f" < "${NOWEB_SOURCE}" > "${NOWEB_CODE}/$f"
done

6.1 Code Chunks

Hauptfunktion
0 1 2 3 5
Hauptmethode
4
build-script
6
Knuth, Donald E. 1984. „Literate Programming“. Comput. J. (Oxford, UK) 27 (2): 97–111. https://doi.org/10.1093/comjnl/27.2.97.
Marneffe, Pierre-Arnoul de. 1973. Holon Programming: A Survey. Univ. de Liège, Service d’Informatique.