Digi Tales

Sotto il vestito, il codice

Ott
28

Digitale ovunque. Nella scuola, nel lavoro, nel divertimento.

Digitale come servizio, come risorsa a disposizione di tutti, appena girato l’angolo di Google.

Tempo fa1 scrivevo che ci sono tre miti che circolano sulla rete:

  • 1) che sia un ambiente naturale,
  • 2) che le risorse che offre sono gratuite e
  • 3) che siano infinite.

Un supermercato infinito, con scaffali pieni di ogni ben di dio, senza nessuno alla cassa. Tanta formazione alla “didattica digitale” si poggia proprio su questi miti: ecco qui un sito per fare i cruciverba, ecco una app per i quiz, ecco una collezione di sfondi animati.

C’è ancora chi proprio non riesce ad adeguarsi al flusso mainstream e si domanda: cosa rende possibile tutto questo? Facile: i computer, prima di tutto, poi i cavi e i satelliti, senz’altro. Ma cos’altro c’è, sotto la superficie?

In un primo senso, sotto ci sono interessi, soldi, potere, che governano questo come altri campi, con buona pace di chi vede solo futuri rosei in cui intelligenze artificiali e persone andranno a braccetto. Non è grazie all’amore della condivisione della conoscenza che possiamo fare ricerche, scambiarci email, tradurre, condividere agende, parlarci a distanza senza spendere un euro. Ed è curioso che quasi nessuno – in un mondo così attento al profitto, alla conquista di ogni possibile mercato – metta in questione tutta quest’abbondanza di risorse gratuite; non solo quelle create e condivise da docenti-artigiani di buona volontà, ma anche quelle che richiedono enormi centri di calcolo solo per essere distribuite. Cosa ottengono le grandi imprese in cambio di questi servizi gratuiti? Da dove traggono le risorse economiche per restare in piedi? Per quanto tempo questi servizi resteranno gratuiti?

In un altro senso, sotto tutti questi servizi c’è il codice sorgente: un testo che fa funzionare i computer, raccoglie e trasforma dati, inventa mondi e connette persone. Anche oggi, nell’era delle interfacce ammiccanti, dei podcast, dei videotutorial, quello che c’è sotto è sempre un testo. Proprio così: solo lettere, numeri e segni di interpunzione, perché è di questo che sono fatti tutti i programmi che fanno girare il mondo, dagli smartphone ai satelliti. E questo non è tanto strano in una cultura in cui il paradigma dominante è ancora il libro scritto.

Oggi, molto più di ieri, siamo letteralmente (!) immersi in un mondo di testi. Solo che non lo sappiamo, o non vogliamo saperlo. La superficie è molto più rassicurante. Secoli di divisioni tra tecnica e umanesimo, tra estetica ed etica ci hanno abituato a disinteressarci di quello che c’è sotto il cofano della macchina. Il design dei dispositivi che ci rendono possibile lo stile di vita occidentale punta a nascondere sotto superfici lisce, morbide, dai colori tenui, tutto quello che potrebbe disturbarci perché ci ricorda che non lo capiamo.

Perché questi testi che governano il nostro mondo sono incomprensibili per il 99,6% della popolazione mondiale (oggi ci sono circa trenta milioni di programmatori nel mondo, che su 8 miliardi di abitanti del pianeta circa fa appunto lo 0,4 %). Questi trenta milioni sono gli unici esseri umani in grado di verificare (leggendolo) cosa fa un programma. Se, per ipotesi, venissero tutti sostituiti da software in grado di programmare al loro posto,2 avremmo un mondo perfetto di cui non saremmo più in grado di riprendere il controllo. Questo secondo senso si incastra perfettamente col primo: se otteniamo tutto quello che ci serve gratis, non c’è più bisogno di capire come funziona.

Ma sapere cosa davvero c’è sotto è importante anche per avere una conoscenza di una parte di attività umana che ci sfugge. Il codice sorgente non è fatto di 0 e di 1, come ancora si legge da qualche parte; magari sottintendendo che siccome usano un codice binario i computer possono scegliere solo tra due cose, bianco e nero, senza capire le sottigliezze, le sfumature: insomma sono stupidi. Sarebbe come dire che la lingua italiana è composta solo da una trentina di suoni e quindi non può esprimere più di trenta concetti. 0 e 1 sono le lettere di un alfabeto, con il quale si compongono parole, frasi, testi e intere biblioteche. Non è vero che computer capiscono solo 0 e 1: non li capiscono affatto. Invece capiscono istruzioni complesse, descrizioni di situazioni, condizioni, specifiche di azioni, purché appartenenti ad uno degli ottomila linguaggi di programmazione oggi esistenti e purché rappresentate con l’alfabeto più semplice possibile: quello appunto a due simboli. Sotto sotto il punto importante non è l’esistenza di due soli simboli, ma che i computer usino una logica a due valori per eseguire un algoritmo semplice come: “se questo valore è maggiore di 37 fai questo, altrimenti fai quest’altro” o uno più complesso, come quello che riconosce un viso. Qui però i computer digitali c’entrano poco: anche i primi computer, che erano analogici, si basavano sulla cosiddetta algebra di Boole (1847), che ha solo due valori. Dietro all’idea di effettuare un calcolo per decidere la verità di una proposizione c’è il neopositivismo, le tavole di verità del primo Wittgenstein, e poi indietro Leibniz, e poi Ramon Llull, e indietro “Sic et non” di Abelardo, e ancora prima le Confutazioni Sofistiche di Aristotele, fino alla dicotomia di Parmenide tra l’Essere e il non Essere. E il fatto che usino una logica a due valori non impedisce affatto ai software di produrre risultati con un grado di certezza limitato o valutazioni probabilistiche.

Quando oggi gli esseri umani scrivono il codice sorgente di un programma non usano 0 e 1, né quelle strane parolette incomprensibili (MOV, PTR, JMP) che sono solo delle etichette più facili da ricordare per ordinare al processore di spostare dati da un registro all’altro. I linguaggi che si usano oggi sono flessibili, complessi. Permettono di scrivere regole e fatti, di definire funzioni, di costruire classi di oggetti che ereditano conoscenze. Non sono nemmeno tutti ispirati all’inglese, come ancora qualcuno crede: ci sono linguaggi basati sul francese, sul finnico, sull’arabo, sul cinese.

I linguaggi di programmazione vengono inventati continuamente, a differenza delle lingue naturali. Spesso un linguaggio viene inventato per fornire ai programmatori uno strumento più veloce e pratico, o più flessibile e potente; a volte per fornirne uno più elegante e piacevole. Perché i linguaggi sono creati da esseri umani per altri esseri umani, non per i computer. Tant’è che ci sono linguaggi inventati per gioco, per divertimento, per mostrare quanto si è intelligenti e sfidare gli altri, ed hanno nomi come Malebolge, Shakespeare, LOLCAT, Chef o Cow. Questa classe di linguaggi, detti pomposamente “esoterici”, sono praticamente inutili, ma svolgono una funzione puramente estetica, alla faccia di chi sostiene che l’informatica è una tecnica senz’anima. L’esistenza di questi linguaggi dice anche molto sul fatto che gli esseri umani riescono a divertirsi anche facendo le cose più serie, e non resistono a prendersi in giro da soli.

Anche i codici sorgenti non sfuggono a questa legge: i testi dei programmi non sempre sono “algoritmi codificati in un linguaggio per risolvere un problema”, come vorrebbero i manuali. Ci sono programmi che non risolvono nulla, ma sono opere d’arte, scherzi, poesie. Sì, poesie: perché l’estetica si infila in ogni attività umana, in particolare quando si mette di mezzo un linguaggio.

Certo viene la curiosità, soprattutto per una scuola che ospita iniziative di Coding e che propone l’apprendimento del pensiero computazionale per preparare le generazioni future di programmatori (o almeno così pensa): ma chi sono allora questi programmatori? Sono sacerdoti della Macchina Divina che si aggirano in camice bianco? Sono hacker quindicenni e brufolosi che scatenano guerre nucleari spiattellando i segreti della CIA? Sono nerd bianchi etero che vivono solo per schiacciare tutti gli altri con la forza della loro conoscenza ultra-specialistica? Questi sono i luoghi comuni che costituiscono il nostro immaginario collettivo e che provengono dal cinema e dalla letteratura di fantascienza. Ma i programmatori sono anche altro: sono ragazzini e vecchietti, cinesi e russi, donne (poche, purtroppo) e altri generi, geni e principianti, creativi e precisini. Scrivono in maniera diversa, anche per ottenere lo stesso risultato, in base alla loro storia, alla loro lingua madre, alle preferenze stilistiche, alla fase della loro vita. Esattamente come ciascuno di noi scrive diversamente un messaggio d’amore e una velenosa lettera all’amministratore di condominio.

Il fatto è che ancora se ne sa poco: è un campo che non è studiato allo stesso modo, poniamo, di quello della letteratura tradizionale. Non esiste una “sociolinguistica” del codice sorgente.

Di tutti questi temi si è occupato CodeFest 2021, il festival online che si è svolto tra il 27 Settembre e l’8 ottobre 2021. Un Festival unico al mondo, organizzato insieme dall’Università di Torino e dall’associazione Codexpo.org. Riflessioni, concerti, spettacoli, laboratori in cui si affrontano l’estetica digitale, la conservazione del patrimonio, le sfide sociali, le infinite possibilità della scrittura. Tutto per cercare di sfatare il mito della programmazione come roba da macchine, per cercare di raccontare un’altra avventura dell’umanità alla ricerca della perfezione.

Altre informazioni, ma pure le registrazioni degli eventi, le potete trovare su https://codexpo2021.lynxlab.com .

1Le tre fallacie della rete, in “Una scuola per la cittadinanza. Volume 2: Gli orizzonti di senso”, a cura di Mario Ambel. PM Edizioni, 2020, pagg. 178-184.

2Come provo a raccontare in La fine della formazione, https://www.stefanopenge.it/wp/?p=912

Garibaldi e i linguaggi napoleonici

Mag
18

I programmatori, a differenza degli eroi, sono persone normali, anche se a volte non sembra. Come tutte le persone normali hanno preferenze, fastidi, passioni, fobie. Queste idiosincrasie del tutto umane vengono applicate ai linguaggi di programmazione, agli strumenti per scrivere programmi, agli stili in cui si scrivono. Per questo, forse, sono stati creati così tanti linguaggi di programmazione (circa 8.000).

Una delle discussioni che durano da più tempo è quella sul modo migliore per programmare. In breve, si tratta della metafora generale con cui si pensa al rapporto tra umano e computer durante la programmazione. Ci sono almeno questi quattro modi maggiori:

Napoleonicol’umano ordina e il computer esegue
Aristotelicol’umano definisce regole e fatti e il computer trae le conseguenze e dimostra teoremi
Leibnizianol’umano progetta funzioni e il computer le calcola
Shakespearianol’umano descrive una situazione in cui degli attori che hanno una conoscenza limitata del mondo sanno compiere alcune azioni e interagire tra loro; il computer sovraintende a questa sessione

Il primo modo è quello che si insegna di solito per primo, ed è anche quello che spesso viene usato per definire il significato di “computazionale”: ci si immedesima nel computer e si cerca di descrivere come farebbe a risolvere il problema con le informazioni che ha. Gli altri modi cercano di venire incontro agli umani, al nostro modo di pensare. Il vantaggio di questi altri paradigmi dal punto di vista didattico è che permettono di scrivere un programma in maniera più naturale, descrivendo il problema, anziché la soluzione. Sono i computer a dover avvicinarsi agli umani, non viceversa. E questo vale anche, e soprattutto, quando si fa coding con dei ragazzini.

Snap! permette molti modi (tranne quello Aristotelico), anche se i suoi autori mostrano una preferenza spiccata per il terzo modo, quello Leibniziano. Nota: il nome tradizionale per questi modi è “paradigma”, e di solito si usano etichette un po’ meno fantasiose per indicarli. Ma qui non stiamo facendo un corso di informatica.

Siccome queste sono parole un po’ astratte, facciamo qualche esempio.

Il contesto è la canzoncina “Garibaldi fu ferito” che una volta i bambini sapevano a memoria e cantavano sull’aria della Canzone dei Bersaglieri. Il gioco era quello di sostituire tutte le vocali delle parole con una sola, ottenendo ad esempio “Garabalda fa farata” oppure “Gurubuldu fu furutu”, eccetera. I bambini sanno farlo, anche se non sanno esattamente dire come. Prima di continuare potete provare anche voi, e interrogarvi su come avete fatto.

Come facciamo per far fare la stessa operazione ad un computer? Per quello che abbiamo detto sopra, non c’è un solo modo, né un modo “giusto” (questo è uno dei motivi per cui fare coding ha un senso forte solo se non ci si limita a ricopiare tutorial e eseguire esercizi). Possiamo provare a seguire almeno tre strade diverse, per poi magari valutarne la semplicità, l’utilità in termini didattici, e se fossimo informatici anche l’efficienza.

I blocchetti realizzati in Snap! delle varie versioni potete vederli e provarli direttamente da qui:

https://snap.berkeley.edu/project?user=stefano63&project=Garibaldi%20fu%20ferito

Prima versione, imperativa

  1. prendi il testo della canzoncina
  2. conta la lunghezza del testo il lettere (sono 90)
  3. prepara una variabile – vuota – dove andrà a finire la versione trasformata
  4. prepara una variabile che servirà a contare le lettere e mettici dentro 1
  5. ripeti novanta volte:
    1. prendi la lettera I del testo
    2. se è una vocale, sostituiscila con la A, e mettila all’inizio della variabile finale
    3. altrimenti, metti la lettera originale all’inizio della variabile finale
    4. aumenta I di 1
  6. quando hai finito, restituisci la versione trasformata

La parte da 5.2 a 5.3 può essere affidata ad una funzione a parte (l’abbiamo chiamata “cambia vocale con…”) per evitare di rendere i blocchetti troppo complicati da leggere. E’ una funzione molto semplice, che si limita a verificare che una lettera sia una di queste: a,e,i,o,u. Non tiene conto delle maiuscole né delle vocali accentate.

Seconda versione, ricorsiva

Un’altra versione possibile è quella che sfrutta una caratteristica di alcuni linguaggi di programmazione, cioè la possibilità di richiamare una funzione al suo stesso interno. In pratica, si usa la tecnica di dividere un problema in sotto-problemi sempre più piccoli finché non si arriva ad un problema risolvibile.

In questo caso, sappiamo come trasformare una lettera (con la funzione “cambia vocale con”) ma non sappiamo come trasformare un intero testo.

  1. se la frase ha lunghezza 1 (cioè è se è composta da una sola lettera) si applica la funzione “cambia vocale con” e si restituisce il risultato (questo è il passo in cui sappiamo come risolvere il problema);
  2. altrimenti, si chiama di nuovo la stessa funzione “cambia frase” ma passando due valori diversi:
  • la prima lettera della frase
  • tutto il resto della frase
  1. si unisce il risultato che proviene da queste due funzioni e lo si restituisce

Una volta superato lo shock di un programma che non si capisce come fa a funzionare, la soluzione è di una semplicità imbarazzante.

Terza versione, funzionale

In questo caso si sfruttano due caratteristiche di Snap!, tipiche dei linguaggi funzionali:

  • la possibilità di applicare una funzione su tutti gli elementi di una lista, uno per uno, ottenendo una nuova lista
  • la possibilità di ridurre una lista ad un solo elemento, applicando un’operazione agli elementi, due alla volta.

Anche in questo caso l’algoritmo è molto semplice ed è basato su una concatenazione di funzioni:

  1. si applica la funzione “cambia vocale ” alla lista ottenuta separando la frase ad ogni lettera
  2. si combinano gli elementi di questa lista in una nuova frase e la si restituisce

Preferenze per uno dei tre? Quale vi sembra più chiaro? Quale vi sta più simpatico?

A me, personalmente, l’ultimo. Proprio perché non si perde a misurare, a tenere il conto del punto in cui siamo arrivati, non ha bisogno di appoggiare il risultato parziale da qualche parte. In fondo non fa altro che trasformare in blocchetti quello che volevamo fare: applicare una trasformazione a tutte le vocali di un testo.

A proposito: che ne è di quel famoso adagio “I computer sono stupidi, sanno fare solo una cosa e la fanno sempre nello stesso modo”?

Pensiero computazionale sì o no? Boh, dipende dal linguaggio.

Gen
27

Una delle motivazioni dietro la spinta all’introduzione della programmazione dei computer in giovane età (=coding) è quella per cui questa pratica insegna il pensiero computazionale, che è un modo di affrontare i problemi in maniera scientifica. Anche se Jeannette Wing si è affannata a dire che non si tratta di insegnare ai bambini a pensare come i computer, e Seymour Papert a predicare che bisogna insegnare ai computer come se fossero bambini, questo tema resta nell’aria. Computazionale significa “razionale, finito, corretto, misurabile” eccetera. In pratica, imparare il pensiero computazionale significa, per ogni problema, saper immaginare un algoritmo che lo risolva. Questo algoritmo deve essere eseguibile praticamente da un computer: non deve contenere errori, non deve basarsi su termini ambigui, non deve richiedere un tempo infinito o una memoria infinita per arrivare alla soluzione.

Però gli algoritmi si pensano (e poi si scrivono) diversamente a seconda del linguaggio, e a seconda del tipo di linguaggio che si ha in mente. Usare un linguaggio semplice quando si è ai primi passi è sicuramente una buona idea; ma cosa significa “semplice”? Può significare che costringe ad usare dei concetti e delle operazioni di base, vicine a quelle che sa fare il computer; oppure che spinge a nascondere i dettagli e a concentrarsi “semplicemente” sulla struttura dei dati e sugli obiettivi.

Insegnare ai bambini una forma di pensiero computazionale che li abitua a pensare nei termini del primo significato di “semplicità” rischia di creare più problemi – in futuro – di quelli che risolva adesso.

Voglio provare a spiegare questa differenza con un piccolo esempio.

Partiamo da Snap!, un ambiente di programmazione che pochi conoscono, che assomiglia molto a Scratch (ne è derivato) ma ha delle differenze importanti. Intanto è nato all’Università di Berkeley, dall’altra parte degli USA rispetto a Stanford, dove è nato Scratch. Poi ha un target più ampio, nel senso che può essere usato da bambini ma anche da ragazzi più grandi, perché è basato su un modello di linguaggio più potente di quello che sta sotto Scratch. Le differenze tra Snap! e Scratch sono poco visibili ad un primo approccio (si possono disegnare girandole o creare scenette animate con entrambi), ma sono molto profonde. Ne elenco solo tre fondamentali:

  1. A differenza di Scratch, in Snap! si possono creare funzioni, cioè procedure che alla fine restituiscono un valore, e questo è molto comodo perché permette di costruire delle catene di funzioni che si applicano ai risultati di altre funzioni.
  2. In secondo luogo, in Snap! ci sono delle funzioni per creare e gestire vere liste (di numeri, di lettere, di parole, ma anche di sprite, o di qualsiasi oggetto).
  3. Inoltre le funzioni possono essere usate come oggetti da altre funzioni. In altre parole: una funzione si può applicare non solo a oggetti semplici (come numeri, lettere) ma anche ad altre funzioni. In aritmetica conosciamo questo tipo di cose: la moltiplicazione è l’applicazione ripetuta della funzione somma.

Il terzo punto è particolarmente utile quando si vogliono trattare delle serie di dati. Se vogliamo trasformare una lista di numeri, o di lettere, o di parole, in qualche altra cosa dobbiamo applicare una trasformazione ad ognuno degli elementi della lista per ottenere una nuova lista; avere un linguaggio che permetta di fare direttamente questo tipo di operazioni permette di concentrarsi sul problema, e non sul meccanismo delle soluzione.

Mettiamo, per esempio, di voler generare la lista dei quadrati dei primi 10 numeri interi. Partendo da una lista di numeri interi, vogliamo moltiplicare ogni numero per se stesso. Cioè da 1,2,3,4,5… vogliamo ottenere 1,4,9,16,25 …

Questo in Scratch si può fare così:

  • crea una lista di numeri interi e dagli il nome “numeri”
  • crea una seconda lista e dagli un nome “quadrati”
  • crea un contatore e dagli il nome “i”, e valore 0
  • ripeti tante volte quanto è la lunghezza della lista “numeri”:
    • aumenta “i” di 1
    • moltiplica l’elemento i della lista “numeri” per se stesso
    • aggiungi il risultato alla lista “quadrati”

Saltando la parte di creazione delle variabili, ecco i blocchetti:

E’ semplice, sì, ma è anche un modo di pensare molto meccanico, che segue esattamente quello che succede “sotto il cofano”. Siamo noi che ci adeguiamo al modo di lavorare del computer, e non viceversa. Arrivare a questa formulazione non è banale: bisogna imparare a pensare in un certo modo. Bisogna imparare il concetto di contatore, di indice di una lista, quello di ciclo, di test di terminazione, eccetera. Sono gli elementi di base della programmazione classica.

Proprio questo è uno dei limiti dell’approccio “computazionale” di cui parlavamo sopra: si impara a pensare come un computer, o meglio secondo gli schemi che il linguaggio di programmazione che usiamo (in questo caso Scratch) mette a disposizione.

Da un lato questo apprendimento ha degli aspetti positivi: ogni volta che ci poniamo un limite impariamo nuovi modi di risolvere problemi. Dall’altro, restare dentro quei limiti non ci permette di andare molto lontano. Potrebbe esserci (non è mai stato studiato a fondo) una forma di imprinting per cui il primo modello di programmazione imparato resta quello fondamentale, un po’ come la lingua madre. Se i bambini imparano a usare i cicli per scorrere le liste, poi continueranno a farsi venire in mente questa modalità anche in futuro.

Ma usare i cicli è solo uno dei possibili modi di risolvere il problema dei quadrati. Ce ne sono altri, che dipendono dal linguaggio che si usa.

In Snap! si possono disporre i blocchetti esattamente nello stesso modo che in Scratch:

Ma si può fare anche qualcosa di diverso, più semplice e soprattutto più vicino alla struttura del problema.

Per risolvere il problema dei quadrati dei numeri interi non siamo costretti a pensare in termini di contatori e di indici, non dobbiamo per forza preoccuparci di sapere quando fermare il processo, dove mettere i risultati. Queste sono cose che riguardano la meccanica dell’algoritmo, non il problema in sé.

Qual era la cosa che volevamo fare, l’idea iniziale? Applicare la funzione “moltiplica per se stesso” a tutti gli elementi di una lista. Bene, allora cominciamo dalla lista

Questo blocchetto è una funzione che restituisce una lista costruita con gli oggetti che mettiamo negli spazi bianchi, in questo caso i primi cinque numeri interi. Non abbiamo bisogno di creare una variabile perché la funzione restituisce sempre quello che ci serve. Ora possiamo disporre i blocchetti in modo da rispettare esattamente l’idea originale di applicare la moltiplicazione alla lista:

Finito. Non c’è altro da fare. Questo blocchetto (“applica”) fa da solo tutto il lavoro: prende il primo elemento della lista, lo inserisce nei due buchi del blocchetto verde, esegue la moltiplicazione e mette da parte il risultato, poi passa al successivo. Alla fine restituisce una nuova lista con i risultati.

La presenza del blocchetto “applica” è una delle caratteristiche di Snap! (e dei linguaggi funzionali a cui si ispira) a cui facevamo riferimento prima. E’ una funzione che lavora su altre funzioni. Usando questo approccio, non ci servono variabili, contatori, cicli. Per certi versi, è molto più intuitivo e vicino al problema questo approccio di quello precedente, in cui dovevamo introdurre una serie di concetti di supporto.


In Snap! c’è un’altra maniera di ottenere questo risultato, ancora più semplice di quella che abbiamo visto adesso. Torniamo all’idea di partenza: “moltiplicare ogni numero di una lista per se stesso”. Ma invece di moltiplicare ogni numero per se stesso, possiamo partire da due liste identiche, e moltiplicare ogni elemento della prima lista per il corrispondente elemento della seconda.

Proviamo a fare esattamente questo:

Il risultato è lo stesso. In sostanza, l’operazione “moltiplicazione” normalmente si applica a dei numeri; ma in Snap! è stata estesa per applicarsi anche a delle liste. Naturalmente potremmo pensare di utilizzarla anche per moltiplicare due liste diverse, o per moltiplicare una lista per un numero singolo. Forse funziona anche con altre operazioni? Proviamo con l’operazione “elevamento a potenza”:

Funziona. Ed è abbastanza chiaro che è molto più semplice di tutto l’ambaradam che avevamo dovuto mettere in campo prima. Questa modalità ci libera di tutta la parte meccanica e ci spinge invece verso una maniera diversa di concepire il problema che volevamo risolvere, che a sua volta ci apre la strada verso altre possibilità.

In conclusione: attenzione al linguaggio che si sceglie, e non confondiamo la razionalità con la meccanicità.

Tecniche e tecnologie per la fantasia

Dic
11

Fantasia e tecnica non vanno d’accordo, si direbbe. Meno ancora fantasia e tecnologia: se c’è una, scompare l’altra. Quando entra in campo la tecnologia, il libero gioco dell’immaginazione dove va a finire? Però, però…

La tecnica del sasso nello stagno è descritta da Gianni Rodari nel secondo capitolo della Grammatica della Fantasia, come parte dello strumentario che serve a chi vuole inventare storie per i bambini, o con i bambini.
E’ una tecnica fondata sulle relazioni che uniscono parole nella mente, ma anche sul potere del caso nel sorprenderci e generare l’inizio di una storia.

Si pensa una parola… o meglio: la si chiede a qualcuno che passa di là, oppure la si pesca da un dizionario, o da un libro. Perché un libro? Perché è ancora più casuale, e dunque più sorprendente. Apri il libro a pagina 27, prendi la terza parola della quinta riga.
Poi si parte da quella parola per esplorare una serie di associazioni che servono a far emergere altre parole.
Per esempio, partendo da stasera possiamo andare a cercare:

le parole che cominciano allo stesso modo: stabilire, staccare, stagione, storia, studiare, stupido, …

le parole che finiscono allo stesso modo , cioè che sono più o meno in rima con stasera: camera, eccetera, lettera, maniera, opera

le parole simili, che si usano nello stesso contesto: stamattina, stanotte, prima, dopo, più tardi

E già nasce una storia:

Stasera, in camera, apro una lettera: sempre la stessa storia, la solita maniera, come un’opera eccetera eccetera – stupido! –

fino ad usare la lettere che compongono la parola per fare un acrostico:

  • Strada
  • Treno
  • Anima
  • Sangue
  • Egli
  • Ritornare
  • Appunto

Tutte queste parole nuove possono essere usate per creare una storia o una filastrocca.
Posiamo programmare un computer per fare (almeno una parte di) queste operazioni?
Sì, ed è quello che ho fatto qui con iKojo, la versione online di Kojo:
http://ikojo.in/sf/vylXgjC/10
Cliccate su RUN, prendete nota delle parole che vengono fuori (compreso l’acrostico) e poi iniziate a scrivere.
A me, partendo dall’acrostico di sopra – generato appunto dal programma – viene in mente una storia titanica (nel senso del film):

Lui è partito, col treno, chissà quanta strada ha fatto, ma ama lei fin nel profondo dell’anima. Lo ha giurato col sangue. Le aveva detto che sarebbe tornato, una sera di queste, e appunto, stasera…

Fa piangere già così, immaginate se poi lui stasera non dovesse arrivare …

Un altro risultato del Sasso nello Stagno

Il binomio fantastico è un’altra tecnica notissima, sempre dai primi capitoli della Grammatica.
Qui si prendono due parole a caso, possibilmente dalla mente di due persone diverse, o ancora una volta da un dizionario, da un giornale (dal web?).
Gli esempi di Rodari riguardano due sostantivi, ma non si vede perché non si potrebbero usare aggettivi o verbi; anzi, ci sono splendidi esempi di applicazione di questa variante nei racconti che mettono in scena i gemelli terribili, Marco e Mirko: “il leone bela”, “il lupo è dolce”, “il cielo è maturo”.
I due sostantivi si mettono insieme usando delle preposizioni: con, di, su, in (ma io aggiungerei: sotto, sopra, con, senza…).
Cosa fanno? si incontrano, si scontrano, vanno d’amore e d’accordo?
Per esempio: sasso, stagno (guarda un po’ che fantasia…)

  • il sasso nello stagno
  • il sasso di stagno
  • il sasso sotto lo stagno
  • lo stagno del sasso
    eccetera.

Ogni frase può essere l’inizio di una storia.
A me il sasso di stagno piace molto, mi fa pensare ad una palla di carta stagnola, di quelle della cioccolata, che usavo per giocare a calcio in corridoio da piccolo. E’ un sasso gentile e bellissimo, luccica come una pepita.

Una volta un minatore che lavorava a Canale Serci, sul monte Mannu, volle fare una sorpresa a suo figlio di tre anni e gli portò un sasso di stagno. Ma non era un sasso, era …

Se preferite, partiamo con una filastrocca. Il sasso di stagno richiama subito un ragno dispettoso, forse geloso, ma di chi? facile: di un cigno

Quel sasso di stagno
tirato da un ragno
geloso di un cigno
più bianco del regno…

Di nuovo vi chiedo: potremmo programmare un computer per fare (almeno una parte di) queste operazioni?
Sì, ed è quello che ho fatto qui:
http://ikojo.in/sf/EnNhE3O/12
Cliccate su RUN e state a guardare.


Sull’importanza del caso, sulla sua magia che ci costringe a renderci conto di quello che siamo (esseri che non possono impedirsi di dare senso a qualsiasi configurazione casuale, che vedono strutture chiuse ovunque) e sulla sua importanza per la didattica ho già scritto qui.

Se date un’occhiata al codice sorgente (a sinistra) vedete che a dispetto della semplicità apparente c’è invece parecchio lavoro sotterraneo per riuscire a mettere un articolo davanti ad un nome, o per costruire la preposizione articolata corretta. Non perché sia difficile la programmazione: perché è difficile la grammatica italiana, che deve dar conto di quasi mille anni di storia, di prestiti, di varianti locali, di sovrapposizioni. Anche questo è un esercizio di coding interessante, che richiede riflessione su come funzionano i meccanismi della lingua per poterli trasformare in algoritmi. Non è sempre necessario ricostruire tutto da capo, si può partire da pezzettini già pronti – è quello che ho fatto io e che fa chiunque programmi un computer.
L’idea più generale di accoppiare a caso sostantivi, proprietà, azioni, luoghi sta all’origine delle creazione di Limericks casuali a partire da una struttura (sintattica, ma anche narrativa): qualcuno, in qualche posto, fa qualcosa, e allora succede qualche altra cosa. Come finisce? E’ lo schema di tanti giochi, e anche delle fiabe a ricalco, un’altra tecnica descritta nella Grammatica della Fantasia nel capitolo 21 (ma ripresa anche in molti di quelli seguenti).
Entrambe queste possibili “applicazioni rodariane” del coding le ho descritte in “Lingua, coding e creatività”, che è un libro che cerca di scardinare l’idea che fare coding sia solo un’attività carina o che si debba fare solo per studiare le STEM; i codici sorgenti relativi, in Logo, Prolog e Kojo, sono nel sito di accompagnamento al libro e li possono scaricate tutti.

Bene, ora arriva la domanda cruciale: ma se usiamo un computer per tirar fuori tutte queste parole, non stiamo limitando la creatività nostra o dei bambini?
Io non credo. Per due motivi che mi pare possano fondarsi proprio su quello che Rodari ha scritto, come ho cercato di spiegare in “Rodari digitale“, l’ultima fatica di quest’anno.

Primo: la parte creativa non è quella di andare a cercare le parole, ma quella di costruire la storia. La ricerca delle parole è la parte meccanica, che richiede l’accesso ad un archivio di parole e alcune regole. Altrimenti basterebbe avere nove parole per fare una poesia (“Si sta come d’autunno sugli alberi le foglie”).

Secondo motivo: non sto proponendo di usare un programma bello e pronto, e nemmeno di cominciare da zero. Propongo di partire da un codice sorgente che funziona, ma di metterci le mani da subito. Cambiando le parole di partenza, cambiando le regole (per esempio: solo sostantivi o anche verbi? quali preposizioni?). Variando la tecnica: tre parole invece di due; oppure aggiungendo i prefissi e i suffissi, i diminutivi e vezzeggiativi.

Terzo motivo (non era previsto, ma lo aggiungo lo stesso): un computer sarà pure ottuso, ma non c’è limite alle cose creative che possono fare un umano e un computer, insieme.

Ambiguità felice dei linguaggi

Feb
23

C’è una barzelletta che gira da tempo sui programmatori, esseri inadatti al mondo reale. Dice così:

La mamma dice a Pierino: vai al mercato e compra 2 litri di latte. Se ci sono le uova, comprane 6.
Pierino va e torna con 6 litri di latte.
La mamma: Perché hai comprato 6 litri di latte?
Pierino: Perché c’erano le uova.

Finite le risate per la risposta di Pierino (che immaginiamo essere il risultato di una specie di programma: IF ci sono le uova THEN comprane 6), ci accorgiamo che il problema è in quella particella “ne”, che è un riferimento pronominale. Di quelle cose che abbiamo detto prima. Un link, una URL relativa.
In Italiano, di solito, si riferisce all’ultimo sostantivo utilizzato. Quando ce ne sono più di uno (di che? di sostantivi) di solito con un minimo di interpretazione si capisce a quale ci si riferisce.
Se la mamma avesse detto:
[…] Se c’è lo zucchero, comprane 6 litri.
un parlante Italiano avrebbe capito che il riferimento era al latte, perché sa che lo zucchero non si vende a litri.

E’ uno degli aspetti tipici del linguaggio naturale: un riferimento generico può essere comodo in molti casi, ma può creare dubbi in altri. Dubbi che vanno risolti con delle ipotesi, oppure nell’interazione (“Scusa, mamma: 6 di cosa?”).

Si dice che i linguaggi di programmazione, essendo “formali”, non soffrono di queste malattie, anzi sono stati costruiti apposto per esserne immuni. La barzelletta prende in giro proprio questa ottusità dei computer, dei linguaggi, dei programmi. I computer non interpretano i programmi, ma li eseguono rigidamente. Per cui niente libertà, niente interpretazione, niente poesia, solo correttezza e efficienza.

Ma siamo proprio sicuri che sia così? Facciamo un gioco: traduciamo la storiella in un linguaggio molto usato per il web, ovvero PHP (tranquilli: il discorso può essere seguito da chiunque, anche senza nessuna competenza informatica).

$lista = Array (
 latte => 1,
 uova => 6
 );

In questo frammento di codice sorgente viene creato un dizionario ($lista), cioè una set di dati organizzati per coppie chiave/valore (latte=1, uova=6).
Ci si mettono dentro le informazioni e poi si possono estrarre quando servono.
Scrivendo così:

 print_r($lista);

possiamo vedere cosa c’è dentro $lista:

Array
(
    [uova] => 6
    [latte] => 1
)

Oppure, volendo andare più in dettaglio:

 
print_r($lista[latte]);

cioè: scrivi sullo schermo il valore della chiave “latte” nell’array $lista.
Che è, ovviamente, 1.

Se però guardiamo cosa succede dietro le quinte, ci accorgiamo che l’interprete ha segnalato due errori veniali:

PHP Notice: Use of undefined constant latte - assumed 'latte'
PHP Notice: Use of undefined constant uova - assumed 'uova'

E’ un nostro errore di scrittura: le chiavi sono state scritte come se fossero costanti (cioè senza le virgolette che invece accompagnano le stringhe di caratteri), ma non esiste nessuna costante che si chiama latte, né uova. Ma cosa ha fatto l’interprete PHP, oltre a segnalare l’errore? Ha fatto un’illazione, cioè ha supposto che si volesse scrivere:

'latte' =>1,
'uova' => 6

che sembra in effetti l’interpretazione più ragionevole.

Se siamo bravi programmatori e programmatrici, una volta letta la segnalazione correggiamo il codice, e tutto fila liscio.
Anzi, per essere ancora più precisini, creiamo una costante (visto che ci era stato chiesto), ma le diamo un valore un po’ bizzarro:

define('latte',uova);

Cioè: abbiamo definito una costante che ha come nome “latte”, ma come valore “uova”.
Vi sembra confondente? Ma il linguaggi di programmazione sono precisi, no? Quindi nessun problema: da un lato la costante, dall’altro la chiave.
E infatti, se avessimo lasciato le cose come stavano, non ci sarebbero stati problemi. Ma noi abbiamo voluto essere rigorosi e abbiamo creato la costante E messo gli apici intorno alle chiavi.
Ora se chiediamo:

print_r(latte);

(ovvero: qual è il valore della costante “latte”?), otteniamo la stringa “uova”, come prevedibile; mentre se chiediamo di nuovo:

print_r($lista[latte]);

il risultato non è né “uova”, né 1 ma …  6 !
Il che naturalmente ha una sua logica. Si potrebbe dire che l’interprete ha usato il riferimento pronominale nella nostra richiesta, e ha interpretato la chiave dell’array $lista[latte] come la costante “latte” che era stata definita prima. Ma non è quello che volevamo dire. Insomma, dal nostro punto di vista,  si confonde e restituisce 6, cioè interpreta il codice come se avessimo scritto:

print_r($lista[uova]);

Proprio come Pierino.

Ora cambiamo l’ordine delle chiavi:

$lista = Array (
 'uova' => 6,
 'latte' => 1
 );

e chiediamo di nuovo:

print_r($lista[latte]);

Dovrebbe essere uguale a prima, no?
Eh no, adesso il valore restituito è tornato ad essere 1!
Meglio, dite? Insomma… se provate a scrivere:

print_r($lista);

vi accorgete del pasticcio:

Array
(
    [uova] => 1
)

La chiave latte è stata sostituita da uova (con valore 1) e la chiave uova, che avevamo inserito con valore 6, è stata cancellata.

Certo PHP non è un modello di precisione, per un linguaggio di programmazione. Ma insomma: anche un linguaggio di programmazione è soggetto ad una forma di ambiguità referenziale. E questo dipende, come abbiamo visto, dall’ordine in cui vengono inserite le informazioni nel testo.
Come in una qualsiasi lingua naturale…