Modularizzazione Quando abbiamo a che fare con un problema complesso spesso lo suddividiamo in problemi più semplici che risolviamo separatamente, per poi combinare insieme le soluzioni dei sottoproblemi al fine di determinare la soluzione del problema di partenza. Esempio: La moltiplicazione di numeri con molte cifre viene suddivisa in moltiplicazioni cifra per cifra e i risultati di queste ultime vengono combinate insieme mediante addizioni. Questo procedimento è applicabile anche alla programmazione. si suddivide un problema complesso in problemi di volta in volta più semplici una volta individuati (sotto)problemi sufficientemente elementari si risolvono questi ultimi direttamente si combinano le soluzioni dei sottoproblemi per ottenere la soluzione del problema di partenza E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 1
Approccio top-down: si parte dall alto, considerando il problema nella sua interezza e si procede verso il basso per raffinamenti successivi fino a ridurlo ad un insieme di sottoproblemi elementari Approccio bottom-up: ci si occupa prima di risolvere singole parti del problema, senza averne necessariamente una visione d insieme, per poi risalire procedendo per aggiustamenti successivi fino ad ottenere la soluzione globale. I linguaggi di programmazione mettono a disposizione dei meccanismi di astrazione che favoriscono un approccio modulare Astrazione sui dati - il programmatore può definire nuovi tipi di dato specifici per il particolare problema (tipi di dato astratti) in JavaScript gli oggetti, che vedrete nel corso più avanzato. Astrazione funzionale - il programmatore può estendere le funzionalità del linguaggio definendo funzioni che risolvono (sotto)problemi specifici. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 2
Funzioni con stato Le funzioni che abbiamo visto in precedenza (succ, multipli, ecc) sono tutte funzioni il cui corpo (ovvero ciò che la funzione calcola) è un espressione contenente costanti e parametri formali: le funzioni definibili nei linguaggi di programmazione sono più complesse e potenti e consentono di definire vere astrazioni sul calcolo permettono cioè manipolare tutto lo stato della macchina: le funzioni readnum, readstring e write, writeln sono un esempio di manipolazione dell input e dell output rispettivamente. la semantica delle funzioni è l argomento più difficile da comprendere nello studio dei linguaggi di programmazione. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 3
Funzioni con stato - continua Abbiamo comunque le due fasi, definizione e invocazione: la definizione della funzione stabilisce: i nomi e il numero dei parametri formali, il valore calcolato utilizzando il return come abbiamo già visto, ed inoltre: la porzione di stato che la funzione può manipolare, definizione dell ambiente della funzione (scoping statico) come lo stato viene modificato ovvero l operazione astratta, questo avvine consentendo di specificare come corpo della funzione una sequenza di comandi. e la chiamata della funzione come già visto corrisponde all utilizzo della funzione: stabilisce i valori dei parametri attuali, sui quali la funzione viene invocata, calcola un valore ma... provoca, possibilmente, anche una modifica dello stato. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 4
Definizione di funzione Sintassi: intestazione blocco dove l intestazione della funzione definisce nome e parametri formali: function Identificatore(ListaFormali) il blocco è il corpo della funzione ovvero una sequenza di istruzioni {istruzione 1...istruzione k } le istruzioni sono dichiarazioni o comandi Esempio del calcolo del massimo di 3 numeri letti dall input function massimoditre(x,y,z){ var massimo=x; if (massimo<y) massimo=y; if (massimo<z) massimo=z; return massimo; } writeln("il massimo e "+massimoditre(readnum(),readnum(), readnum())); E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 5
Invocazione di Funzione (chiamata, attivazione) Sintassi: identificatore (parametri-attuali) identificatore è il nome della funzione lista-parametri-attuali è una lista di espressioni separate da virgola i parametri attuali devono corrispondere in numero ai parametri formali (non sempre vero in JavaScript) Esempi: chiamate di funzioni var x=3; var v, z, y=1;... if (multiplo(x+3, succ(y))) writeln (...) ; v= multiplo(succ(succ(0)), x%2);... N.B. Una chiamata di funzione è anch essa un espressione, quindi può essere a sua volta un parametro attuale. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 6
Valore di ritorno di una funzione: istruzione return Esempio: Funzione che restituisce il massimo tra due interi. function max(m, n) { if (m >= n) return m; else return n; } Chiamata di max, ad esempio dal programma: var i, j, massimo; i=readnum(); j=readnum(); massimo = max(i,j); writeln("massimo = "+massimo); Il programma chiamante tramite i parametri attuali comunica alla funzione max i valori sui quali calcolare la funzione (il valore delle variabili i,j). La funzione max tramite il valore di ritorno comunica il risultato al programma principale. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 7
Nel corpo deve esserci l istruzione return espressione; la cui esecuzione comporta: il calcolo del valore di espressione: questo valore viene restituito al chiamante come risultato dell esecuzione della funzione la cessione del controllo alla funzione chiamante Osservazioni l esecuzione di return espressione comporta la terminazione dell esecuzione della funzione Esempio: function max( m, n) { if (m >= n) return m; else return n; writeln("pippo"); /* non viene mai eseguita */ } E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 8
Definizioni induttive di funzioni Riprendiamo la definizione induttiva della funzione che calcola la somma di n numeri, vista precedentemente: SommaN(n) = { 0 se n = 0 n + SommaN(n 1) se n > 0 Questa definizione, e tutte le definizioni induttive di funzioni, è immediatamete traducibile in JavaScript, nel seguente modo: function SommaN(n){ if (n==0) return 0; else return n+somman(n-1); } Il programma che invoca la funzione, ad esempio, può essere il seguente: var x=readnum(); writeln("somma di "+x+" numeri ="+SommaN(x)); E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 9
Definizioni induttive di funzioni La funzione precedente ci dà lo spunto per definire una funzione simile che invece di sommare gli n numeri da n a 0, legge n numeri dall input e li somma: LeggiSomma(n) = { 0 se n = 0 readnum() + LeggiSomma(n 1) se n > 0 La traduzione in JavaScript, è ancora immediata: function LeggiSomma(n){ if (n==0) return 0; else return readnum()+leggisomma(n-1); } Il programma che invoca la funzione è del tutto analogo al precedente cambiano solo i messaggi e il nome della funzione. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 10
Induzione strutturale Le funzioni induttive per essere definite correttamente devono avere dei parametri che sono definiti su un dominio su cui è definito un ordinamento. Qual è il dominio nel caso della funzione precedente? è ancora quello degli interi? Il flusso dei dati in input è una sequenza di elementi, ad esempio: numeri 56-4 21 89 o stringhe cane gatto pesce serpente ad ogni read(num/string) il numero di elementi della sequenze diminiuisce di uno. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 11
Induzione strutturale - sequenze Vediamo l esempio della sequenza di numeri 56-4 21 89 dopo una readnum resta -4 21 89 dopo un altra readnum resta 21 89 ecc. il problema è che la sequenza in input è virtualmente infinita, la macchina chiede dati in input e l utente deve fornirli. come faccio a terminare? devo nel programma specificare una condizione di terminazione. Due possibilità, nel caso di sequenze di input. 1. sequenza con un numero fissato di elementi (caso precedente) 2. carattere terminatore (prossimo esempio) E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 12
Induzione strutturale - sequenze Nella funzione precedente: function LeggiSommaN(n){ if (n==0) return 0; else return readnum()+leggisomman(n-1); } Il parametro n della funzione rappresenta il numero di elementi che devo ancora leggere dalla sequenza di input. La terminazione con elemento terminatore è realizzata dalla seguente funzione: function LeggiSommaTer(n){ var x=readnum(); if (x==n) return 0; else return x+leggisommater(n); } Il parametro n in questo caso rappresenta il terminatore. E. Occhiuto Fondamenti Teorici e Programmazione- 437AA pag. 13