Introduzione alla programmazione di Andrea Vallinotto
Dividi et impera
Il processo di trasformazione dei concetti complessi in istruzioni comprensibili dal nostro robottino
Robert segue la regola d'oro già famosa ai tempi di Giulio Cesare: la scomposizione di
ordini composti in procedure più semplici.
Vediamo quindi di tradurre qualcuno dei punti di sopra in istruzioni-Robert.
"1 prendi i soldi (una certa somma)" diventa:
- chiedi al tuo padrone "Quanti soldi devo prendere?"
- memorizza la cifra
- avvicinati al portafoglio
- prendi con una delle mani il portafoglio
- comincia a prendere i soldi
- ripeti il passo precedente finchè non hai raggiunto il valore memorizzato
prima
- rimetti a posto il portafoglio
Il punto subito seguente "recati dal panettiere" diventa:
- apri la porta di casa
- esci dalla porta di casa
- chiudi la porta
- premi il pulsante di chiamata dell'ascensore (la pigrizia si è trasmessa dal
programmatore al programma stesso)
- apri la porta dell'ascensore
- premi il pulsante del piano terreno
- apri la porta dell'ascensore
- esci dalla porta dell'ascensore
- apri il portone
- esci dal portone
- gira a sinistra
- percorri tutto il marciapiede
- guarda la strada: aspetta finchè passano macchine.
- attraversa la strada
- gira a sinistra
- percorri l'isolato fino alla scritta panettiere
- apri la porta del panettiere
- entra
- chiudi la porta (Robert è prigro ma educato)
Un compito apparentemente semplice come quello di andare dal panettiere si
traduce in una lunga sequenza di istruzioni: questo perchè le istruzioni-Robert
sono molto semplici, poco potenti e poco specializzate. Nella realtà informatica
esistono linguaggi molto semplici, in cui una singola istruzione fa poco; ne
esistono altri più specializzati che si occupano di gestire tanti dettagli in
corrispondenza di un'istruzione singola.
Condizioni, cicli e controlli di flusso
Guardando ai due programmi scritti in istruzioni-Robert si notano due cose a
prima vista:
- si ricorre spesso a istruzioni che comportano un ciclo, cioè l'esecuzione
ripetuta di altre istruzioni: "prendi i soldi - ripeti finchè...." oppure
"percorri l'isolato fino...".
- molte sequenze di istruzioni sono spesso ripetute: "apri la porta X; esci
dalla porta X; chiudi la porta X".
Il primo aspetto individua il concetto di flusso, detto anche "Flow". Questo
significa semplicemente che un programma non è una sequenza di istruzioni che
vengono eseguite in ordine strettamente sequenziale, ma a volte ci sono dei
salti, in avanti o all'indietro. E questi salti dipendono da delle valutazioni
precise: il "percorri l'isolato fino al panettiere" se visto ancora più in
dettaglio diventa:
- guarda alla tua destra
- vedi la scritta "Panettiere"?
- se no, avanza di un metro, e torna al punto 1.
- se si, continua col resto del programma.
Ecco che Robert anche se non è particolarmente intelligente, con una semplice
valutazione - il punto 2 - è in grado di trovare il Panettiere, almeno lo
abbiamo diretto sull'isolato giusto. Quello illustrato in esempio è un ciclo
condizionato, ma non è l'unico tipo di flusso possibile.
Possiamo immaginare infatti che Robert trovi il panettiere chiuso: allora dovrà
saltare il punto dell'acquisto del pane per arrivare a quello della verdura;
la sequenza del panettiere verrà saltata senza mai ritornarci.
Le Subroutine
Il secondo aspetto individuato dalla ripetizione di più passi, introduce ad
un altro importante concetto: le procedure o subroutine.
Per comodità (ma anche per convenienza, come vedremo più sotto), sarebbe comodo
raggruppare la sequenza di istruzioni
- apri la porta X
- esci dalla porta X
- chiudi la porta X
in un unico insieme e di trattarlo come se questa fosse una nuova
istruzione-Robert, chiamata "attraversa la porta". Ci permetterebbe di
scrivere una sola riga anzichè tre (ricordiamoci che i programmatori sono
pigri), ma ci metterebbe anche al riparo da possibili errori di battitura che
potremmo fare ogni volta che riscriviamo le tre righe.
A questo tipo di costrutti si dà il nome di "procedure" o "subroutine" o
"funzioni" - hanno tanti nomi perchè sono molto usate, a volte con sfumature
diverse.
C'è anche da considerare un altro aspetto: avendo creato la nuova procedura
"attraversa la porta", possiamo permetterci di fare delle modifiche che
verranno propagate a tutto il programma. Se ad esempio vogliamo prevedere che la
porta sia chiusa, ma che Robert abbia la chiave per aprirla, possiamo modificare
la procedura "attraversa la porta" così:
- prova ad aprire la porta X
- se non si apre, cerca in tasca la chiave per la porta X. Apri la porta.
- esci dalla porta X
- chiudi la porta X
In questo modo, sia che Robert debba aprire la porta di casa che il portone, non
dobbiamo riscrivere tutto da capo.
Quindi è anche conveniente creare le procedure perchè fa diminuire le
possibilità d'errore dà più versatilità.
Ovviamente le procedure possono essere costruite richiamando altre procedure; le
istruzioni di base sono quindi come mattoni molto semplici. Assemblando queste
si costruiscono dei mattoni più grossi (le procedure); unendo ulteriormente
queste si possono costruire mattoni ancora più grossi e così via.
Un esempio relativo al caso chiavi/porta, potrebbe occuparsi di un aspetto
lasciato in sospeso dalla procedura precedente: se Robert non trova la chiave
che cosa deve fare?
Allora si potrebbe costruire una seconda procedura, "apri la porta X con chiave"
che prevede questa possibilità:
procedura "apri la porta X con chiave"
- prendi la prima chiave dalla tasca
- è la chiave della porta X?
- se non lo è, prendi la chiave successiva e ritorna al punto 2. Se non ci sono
altre chiavi, non si può aprire la porta X (fine procedura)
- apri la porta con la chiave (fine procedura)
In questo modo Robert adesso sa come aprire una porta per la quale ha una
chiave; bisogna però modificare in relazione la funzione "attraversa la porta":
- prova ad aprire la porta X
- se si apre, passa al punto 4; se non si apre, richiama la procedura "apri
la porta X con chiave"
- ci sei riuscito? se sì, prosegui. Altrimenti fermati
- esci dalla porta X
- chiudi la porta X
|
|
|