Il Literate programming è un paradigma di programmazione introdotto da Donald Knuth in cui un programma per computer viene fornito come una spiegazione della sua logica in un linguaggio naturale, come l'inglese, intervallata da frammenti di macro e codice sorgente tradizionale, da cui può essere generato codice sorgente compilabile.
Il paradigma del literate programming, come concepito da Knuth, rappresenta un allontanamento dalla scrittura di programmi per computer nel modo e nell'ordine imposti dal computer, e consente invece ai programmatori di sviluppare programmi nell'ordine richiesto dalla logica e dal flusso dei loro pensieri. I literate programs sono scritti come un'esposizione ininterrotta della logica in un linguaggio umano ordinario, proprio come il testo di un saggio, in cui sono incluse le macro per nascondere le astrazioni e il codice sorgente tradizionale.
Gli strumenti per il literate programming (LP) vengono utilizzati per ottenere due rappresentazioni da un file sorgente literate: uno adatto per ulteriori compilazioni o esecuzioni da un computer, il codice "aggrovigliato" o "tangled" e un altro per la visualizzazione come documentazione formattata, che si dice sia "intessuta" o "woven". Mentre la prima generazione di strumenti di literate programming era specifica per un certo linguaggio di programmazione, i successivi sono indipendenti ed esistono al di sopra di questi.
Il literate programming fu introdotto per la prima volta da Knuth nel 1984. L'intenzione principale dietro questo approccio era di trattare un programma come letteratura comprensibile agli esseri umani. Questo approccio è stato implementato presso l'Università di Stanford come parte della ricerca sugli algoritmi e sulla tipografia digitale. Questa implementazione fu chiamata " WEB " da Knuth poiché credeva che fosse una delle poche parole inglesi di tre lettere che non erano già state applicate al computer. Tuttavia, ricorda effettivamente la natura complicata del software delicatamente assemblato da materiali semplici.
Il literate programming consiste nello scrivere la logica del programma in un linguaggio umano con frammenti di codice e macro inclusi (separati da un markup primitivo). Le macro in un file sorgente literate sono semplicemente frasi simili a titoli o esplicative in un linguaggio umano, che descrivono le astrazioni umane create risolvendo il problema di programmazione, e nascondendo blocchi di codice o macro di livello inferiore. Queste macro sono simili agli algoritmi in pseudocodice tipicamente utilizzati nell'insegnamento dell'informatica. Queste frasi esplicative arbitrarie diventano precisi nuovi operatori, creati al volo dal programmatore, formando un metalinguaggio in cima al linguaggio di programmazione sottostante.
Un preprocessore viene utilizzato per sostituire gerarchie arbitrarie, o piuttosto "reti" di macro "interconnesse, per produrre il codice sorgente compilabile con un comando ("tangle" o "groviglio") e la documentazione con un altro ("weave" o "trama"). Il preprocessore offre anche la possibilità di generare il contenuto delle macro e di aggiungere le macro già create in qualsiasi posizione nel testo del file sorgente del programma, eliminando così la necessità di tenere presente le restrizioni imposte dai linguaggi di programmazione tradizionali o di interrompere il flusso del pensiero.
Secondo Knuth, il literate programming fornisce programmi di qualità superiore, poiché obbliga i programmatori a dichiarare esplicitamente i pensieri alla base del programma, rendendo più ovvie le decisioni di progettazione scarsamente ponderate. Knuth afferma anche che il literate programming fornisce un sistema di documentazione di prim'ordine, che non è un componente aggiuntivo, ma è "cresciuto" naturalmente nel processo di esposizione dei propri pensieri durante la creazione di un programma. La documentazione risultante consente all'autore di riavviare i propri processi di pensiero in qualsiasi momento successivo, e consente ad altri programmatori di comprendere più facilmente la costruzione del programma. Ciò differisce dalla documentazione tradizionale, in cui a un programmatore viene presentato un codice sorgente che segue un ordine imposto dal compilatore e da cui deve decifrare il processo di pensiero dietro il programma dal codice e dai commenti associati. Le capacità metalinguistiche del literate programming si sostiene anche che facilitino il ragionamento, offrendo una "visione a volo d'uccello" del codice e aumentando il numero di concetti che la mente può conservare ed elaborare con successo. L'applicabilità del concetto alla programmazione su larga scala, quella dei programmi di livello commerciale, è dimostrata da una edizione del codice TeX come literate program.
Knuth afferma inoltre che il Literate Programming può portare ad un facile porting di un dato software su più ambienti, e cita persino l'implementazione di TeX come esempio.
Molto spesso si chiama erroneamente literate programming il processo di estrazione della documentazione formattata prodotta da un file comune con codice sorgente e commenti - che è propriamente chiamata generazione di documentazione - o ai commenti copiosamente inclusi nel codice. Questo è il contrario del literate programming: il codice ben documentato o la documentazione estratta dal codice segue la struttura del codice, con la documentazione incorporata nel codice; mentre nel literate programming, il codice è incorporato nella documentazione, con il codice che segue la struttura della documentazione.
Questo malinteso ha portato alcuni a sostenere che gli strumenti di estrazione dei commenti, che i sistemi Perl Plain Old Documentation o Java Javadoc, siano "strumenti per il literate programming". Tuttavia, poiché questi strumenti non implementano la "rete di concetti astratti" che si nasconde dietro il sistema di macro in linguaggio naturale, o forniscono la capacità di cambiare l'ordine del codice sorgente da una sequenza imposta dalla macchina in una comoda per la mente umana, non possono essere correttamente chiamati strumenti di literate programming nel senso inteso da Knuth.
Nel 1986, Jon Bentley chiese a Knuth di dimostrare il concetto di literate programming scrivendo un programma in WEB. Knuth produsse un lungo listato monolitico di 8 pagine che fu pubblicato insieme a una critica di Douglas McIlroy di Bell Labs. McIlroy ha elogiato la complessità della soluzione Knuth, e la sua scelta di una struttura di dati (hash trie di Frank M. Liang), ma ha notato che una più pratica, molto più veloce da implementare, debuggare e modificare soluzione del problema richiedeva solo sei righe di script shell riutilizzando utilities Unix standard. McIlroy ha concluso dicendo:
McIlroy ha successivamente ammesso che la sua critica era ingiusta, dal momento che ha criticato il programma di Knuth su basi ingegneristiche, mentre lo scopo di Knuth era solo quello di dimostrare la tecnica del literate programming. Nel 1987, Communications of the ACM ha pubblicato un articolo di follow-up che illustrava il literate programming con un programma C che combinava l'approccio artistico di Knuth con l'approccio ingegneristico di McIlroy, con una critica di John Gilbert.
L'implementazione del literate programming prevede due passaggi:
La tessitura e l'aggrovigliamento vengono eseguiti sulla stessa fonte in modo che siano coerenti tra loro.
Un classico esempio di literate programming è l'implementazione literate del programma standard di conteggio parole wc Unix. Knuth ha presentato una versione CWEB di questo esempio nel capitolo 12 del suo libro Literate Programming. Lo stesso esempio è stato successivamente riscritto per lo strumento di programmazione letterato noweb. Questo esempio fornisce una buona illustrazione degli elementi di base del literate programming.
Il frammento seguente del literate program wc mostra come frasi descrittive arbitrarie in un linguaggio naturale vengono utilizzate per creare macro, che fungono da nuovi "operatori" nel linguaggio di programmazione literate e nascondono blocchi di codice o altre macro. La notazione di markup è composta da parentesi quadre (" <<...>> ") che indicano le macro, il simbolo " @ " che indica la fine della sezione di codice in un file noweb. Il simbolo " <<*>> " sta per "radice", nodo più in alto dal quale lo strumento di programmazione alfabetico inizierà a espandere la rete di macro. In realtà, scrivere il codice sorgente espanso può essere fatto da qualsiasi sezione o sottosezione (cioè un pezzo di codice designato come " <<name of the chunk>>= ", con il segno uguale), quindi un file di un literate program può contenere diversi file con codice sorgente.
The purpose of wc is to count lines, words, and/or characters in a list of files. The
number of lines in a file is ......../more explanations/
Here, then, is an overview of the file wc.c that is defined by the noweb program wc.nw:
<<*>>=
<<Header files to include>>
<<Definitions>>
<<Global variables>>
<<Functions>>
<<The main program>>
@
We must include the standard I/O definitions, since we want to send formatted output
to stdout and stderr.
<<Header files to include>>=
#include <stdio.h>
@
Il dipanarsi dei blocchi può essere eseguito in qualsiasi posizione nel file di testo del programma letterato, non necessariamente nell'ordine in cui sono sequenziati nel blocco racchiudente, ma come richiesto dalla logica riflessa nel testo esplicativo che avvolge l'intero programma.
Le macro non corrispondono ai "nomi di sezione" nella documentazione standard. Le macro nel literate programming possono nascondere dietro di sé qualsiasi blocco di codice ed essere utilizzate all'interno di qualsiasi operatore di linguaggio macchina di basso livello, spesso all'interno di operatori logici come " if ", " while " o " case ". Ciò è illustrato dal seguente frammento del literate program wc.
The present chunk, which does the counting, was actually one of
the simplest to write. We look at each character and change state if it begins or ends
a word.
<<Scan file>>=
while (1) {
<<Fill buffer if it is empty; break at end of file>>
c = *ptr++;
if (c > ' ' && c < 0177) {
/* visible ASCII codes */
if (!in_word) {
word_count++;
in_word = 1;
}
continue;
}
if (c == '\n') line_count++;
else if (c != ' ' && c != '\t') continue;
in_word = 0;
/* c is newline, space, or tab */
}
@
In effetti, le macro possono rappresentare qualsiasi frammento arbitrario di codice o altre macro e sono quindi più generali di una frammentazione top-down o bottom-up o di una sorta di sottosezionamento. Knuth dice che quando ha realizzato questo, ha iniziato a pensare a un programma come a una rete di varie parti.
In un literate program noweb oltre all'ordine libero della loro esposizione, i blocchi dietro le macro, una volta introdotti con " <<...>>= ", possono essere sviluppati successivamente in qualsiasi posto nel file semplicemente scrivendo " <<name of the chunk>>= "e aggiungendo più contenuto ad esso, come illustra il seguente frammento (" più" viene aggiunto dal formatter del documento per la leggibilità e non è nel codice).
The grand totals must be initialized to zero at the beginning of the program.
If we made these variables local to main, we would have to do this initialization
explicitly; however, C globals are automatically zeroed. (Or rather,``statically
zeroed.'' (Get it?)
<<Global variables>>+=
long tot_word_count, tot_line_count,
tot_char_count;
/* total number of words, lines, chars */
@
La documentazione per un literate program viene prodotta come parte della stesura del programma. Invece dei commenti forniti come note a margine del codice sorgente, un literate program contiene la spiegazione dei concetti su ciascun livello, con concetti di livello inferiore rinviati al loro posto appropriato, cosa che consente una migliore comunicazione del pensiero. I frammenti di wc sopra mostrano come si intrecciano la spiegazione del programma e del suo codice sorgente. Tale esposizione di idee crea un flusso del pensiero, come un'opera letteraria. Knuth ha scritto un "romanzo" che spiega il codice del gioco di narrativa interattiva Colossal Cave Adventure.
Il primo ambiente di literate programming pubblicato fu WEB, introdotto da Knuth nel 1981 per il suo sistema di composizione tipografica TeX; utilizza Pascal come linguaggio di programmazione sottostante e TeX per la composizione della documentazione. Il codice sorgente TeX commentato completo è stato pubblicato in TeX: The Program di Knuth, volume B dell'opera in 5 volumi Computers and Typesetting. Knuth aveva usato privatamente un sistema di literate programming chiamato DOC già dal 1979. Si ispirava alle idee di Pierre-Arnoul de Marneffe. Il CWEB gratuito, scritto da Knuth e Silvio Levy, è WEB adattato per C e C++, funziona sulla maggior parte dei sistemi operativi e può produrre documentazione TeX e PDF.
Esistono varie altre implementazioni del concetto di programmazione letterata (alcune non hanno macro e quindi violano il principio dell'ordine della logica umana come punto prioritario):
.hs e .lhs ; quest'ultimo sta per literate Haskell.% here text describing the function:
\begin{code}
fact 0 = 1
fact (n+1) = (n+1) * fact n
\end{code}
here more text
listings LaTeX fornisce un ambiente lstlisting che può essere utilizzato per abbellire il codice sorgente. Può essere utilizzato per definire un ambiente code da utilizzare all'interno di Haskell per stampare i simboli in modo simile a:\newenvironment{code}{\lstlistings[language=Haskell]}{\endlstlistings}
\begin{code}
comp :: (beta -> gamma) -> (alpha -> beta) -> (alpha -> gamma)
(g `comp` f) x = g(f x)
\end{code}