Pipeline programming

Monday, 12 March 07
Avete presente come funziona il sistema UNIX? Ci sono tanti comandi che possono essere utilizzati in pipe, ovvero l'output del primo diventa l'input del secondo che produrra' un output che diventa input del terzo e cosi' via.

Ad esempio se voglio ordinare una lista di nomi contenuti in un file e poi numerarli poteri scrivere:
cat nomi.txt | sort | cat -n
per produrre un output simile a questo:
% cat nomi.txt | sort | cat -n
     1  cane
     2  gatto
     3  lince
     4  orco
     5  panda
     6  topo


Se ci pensate un po' in molti programmi, specialmente se chi li ha scritti e' interessato alla programmazione funzionale o comunque non gradisce utilizzare variabili inutili e una programmazione troppo imperativa, questo tipo di costrutto e' implicitamente presente molto ma molto spesso:
renderhtml(sort(getmessages($db)));
L'output di una funzione viene dato in input a quella piu' esterna e cosi' via. Il metodo funzionale e' piu' generale della pipe di unix perche' non c'e' solo un input e un output per ogni componente della computazione, ma multipli. Ogni funzione puo' prendere piu' argomenti, e ogni funzione puo' restituirne piu' di uno (implicitamente ritornando un oggetto, una lista, un array, o esplicitamente nel caso di alcuni linguaggi).

Nonostante la sua maggiore potenza la sintassi che permette alle funzioni di essere piu' generale della pipe e' brutta da scrivere (bilanciare le parentesi a volte e' una rottura di scatole, aggiungi un nuovo step nella computazione e devi tornare indietro col cursore per racchiudere quanto gia' scritto tra due nuove parentesi) e specialmente da leggere.

Come se non bastasse in moltissimi dei casi in cui le funzioni vengono utilizzati in maniera annidata in realta' non utilizzano la loro potenza a pieno, ma una semantica che potrebbe essere riprodotta con una pipe. Nel caso di sopra:
renderhtml(sort(getmessages($db)));
Potrebbe essere reso come
getmessages($db) | sort | renderhtml
Mi piace tantissimo. Pero' sembra troppo limitativo il fatto che le funzioni devono essere tutte unarie (cioe' che accettano un solo argomento) quando magari e' solo uno dei tanti argomenti che la funzione riceve a provenire in realta' dalla computazione della pipe, ma si potrebbe banalmente usare una sintassi particolare per l'argomento che proviene dalla pipe se necessario.

Per fare un esempio concreto sort potrebbe prendere un secondo argomento che indica il modo in cui ordinare l'input. In tal caso potremmo scrivere cosi':
getmessages($db) | sort(*,DESC) | renderhtml
In questo caso * viene sostituito con l'output che proviene da getmessages che nel nostro ipotetico esempio prende una lista di messaggi da qualche parte (un DB?).

Ovviamente tale sintassi potrebbe benissimo essere utilizzata in contesti piu' complessi, come questo:
intersection($l | unique | trim, getsomedata | somefunc | somefunc(*,$somearg));
In questo caso abbiamo chiamato una funzione binaria che ha come argomenti due computazioni eseguite tramite la pipe.

Sarei davvero contento di vedere questa piccola ma utile astrazione comparire in qualche linguaggio di programmazione diffuso. C'e' un piccolo problema, la pipe | e' un simbolo gia' usato per il bitwise OR, ma qualche simbolo libero e facile da digitare ancora c'e' (ad esempio @).
4046 views*
Posted at 09:14:47 | permalink | 8 comments | print