Title: IL MODELLO CLIENTE / SERVITORE
1IL MODELLO CLIENTE / SERVITORE
2CLIENTI E SERVITORI
- Servitore
- un qualunque ente computazionale capace di
nascondere la propria organizzazione interna - presentando ai clienti una precisa interfaccia
per lo scambio di informazioni. - Cliente
- qualunque ente in grado di invocare uno o più
servitori per svolgere il proprio compito.
3SERVITORI
- Un servitore può
- essere passivo o attivo
- servire molti clienti oppure costituire la
risorsa privata di uno specifico cliente - in particolare può servire un cliente alla
volta, in sequenza, oppure più clienti per volta,
in parallelo - trasformarsi a sua volta in cliente, invocando
altri servitori o anche se stesso.
4COMUNICAZIONE CLIENTE / SERVITORE
- Lo scambio di informazioni tra un
- cliente e un servitore può avvenire
- in modo esplicito tramite le interfacce stabilite
dal servitore - in modo implicito tramite aree-dati accessibili
ad entrambi.
5FUNZIONI
- Una funzione permette di
- dare un nome a una espressione
- rendendola parametrica
- Esempi (pseudo-C)
- float f() 2 3 sin(0.75)
- float f1(int x)
- 2 x sin(0.75)
6FUNZIONI come COMPONENTI SW
- Una funzione è un componente
- software che cattura lidea mate-
- matica di funzione
- f A ? B ? ... ? Q ? S
- molti possibili ingressi (che non vengono
modificati!) - una sola uscita (il risultato)
7FUNZIONI come SERVITORI
- Una funzione
- riceve dati di ingresso in corrispondenza ai
parametri - ha come corpo una espressione, la cui valutazione
fornisce un risultato - denota un valore in corrispondenza al suo nome
8FUNZIONI come SERVITORI
- Esempio
- se x vale 1
- e f è la funzione R ? R
- f 3 x2 x - 3
- allora f(x) denota il valore 1.
9FUNZIONI come SERVITORI
- Una funzione è un servitore
- passivo
- che serve un cliente per volta
- che può trasformarsi in cliente invocando se
stessa
10FUNZIONI come SERVITORI
- Una funzione è un servitore dotato di nome che
incapsula le istruzioni che realizzano un certo
servizio. - Per chiedere al servitore di svolgere il servizio
occorre - chiamare tale servitore (per nome)
- fornirgli le necessarie informazioni
- Come far comunicare cliente e servitore?
11COMUNICAZIONE CLIENTE/SERVITORE
- Nel caso di una funzione,
- cliente e servitore comunicano mediante
linterfaccia della funzione.
12FUNZIONI INTERFACCIA
- Linterfaccia di una funzione comprende
- nome della funzione
- lista dei parametri
- tipo del valore da essa denotato
- è spesso chiamata firma (signature)
- esplicita il contratto di servizio fra cliente e
servitore.
13COMUNICAZIONE CLIENTE/SERVITORE
- Cliente e servitore comunicano quindi
- mediante
- i parametri trasmessi dal cliente al servitore
allatto della chiamata(direzione dal cliente
al servitore) - il valore restituito dal servitore al
cliente(direzione dal servitore al cliente)
14UN ESEMPIO
- int max (int x, int y )
- return xgty ? x y
-
- Il simbolo max denota il nome della
nuovafunzione - Le variabili intere x e y sono i parametridella
nuova funzione - Il valore restituito è un intero.
15FUNZIONI INFORMATION HIDING
- La struttura interna (corpo) di una funzione è
completamente inaccessibile dallesterno. - Così facendo si garantisce protezione
dellinformazione secondo il principio del suo
nascondimento (information hiding)
16FUNZIONI IN UN PROGRAMMA C
- Un programma C è un insieme di funzioni
- ltprogrammagt
- ltunità-di-traduzionegt
- ltunità-di-traduzionegt ltdefinizione-di-funzio
negt ltdichiarazione-di-funzionegt - Il main è semplicemente la funzione, di no-me
prefissato, dove inizia lelaborazione.
17DEFINIZIONE DI FUNZIONE struttura
- Una ltdefinizione-di-funzionegt è definita
- dalla produzione
- ltdefinizione-di-funzionegt
- lttipoValoregt ltnomegt(ltparametrigt) ltcorpogt
18DEFINIZIONE DI FUNZIONE parametri
- Una ltdefinizione-di-funzionegt è definita
- dalla produzione
- ltdefinizione-di-funzionegt
- lttipoValoregt ltnomegt(lt parametri gt) ltcorpogt
- o una lista vuota void
- o una lista di variabili (separate da virgole)
visibili soloentro il corpo della funzione.
19DEFINIZIONE DI FUNZIONE corpo
- Una ltdefinizione-di-funzionegt è definita
- dalla produzione
- ltdefinizione-di-funzionegt
- lttipoValoregt ltnomegt(lt parametri gt) ltcorpogt
ltcorpogt è tutto ciò che sta fra La forma base
è return ltespressionegt
20DEFINIZIONE DI FUNZIONE tipo
- Una ltdefinizione-di-funzionegt è definita
- dalla produzione
- ltdefinizione-di-funzionegt
- lttipoValoregt ltnomegt(lt parametri gt) ltcorpogt
il tipo della funzione deve coinci- dere col tipo
dellespressione che costituisce il corpo della
funzione
21FUNZIONI COME COMPONENTI SOFTWARE NASCITA E MORTE
- Allatto della chiamata, lesecuzione del cliente
viene sospesa e il controllo passa al servitore. - Il servitore vive solo per il tempo necessario
a svolgere il servizio. - Al termine, il servitore muore,e lesecuzione
torna al cliente.
22CHIAMATA DI FUNZIONE
- La chiamata di funzione è unespressione
- della forma
- ltnomefunzionegt ( ltparametri-attualigt )
- dove
- ltparametri-attualigt ltespressionegt ,
ltespressionegt
23CHIAMATE DI FUNZIONE ESPRESSIONI
- Linvocazione di una funzione da parte di un
cliente costituisce un particolare tipo di
espressione.
24RITORNO DA FUNZIONE
- Listruzione return provoca la restitu-zione del
controllo al cliente, unitamente al valore
dellespres-sione che la segue. - Eventuali istruzioni successive alla return non
saranno mai eseguite!
25IL PROBLEMA DEI SIMBOLI
- f(x) g( f(x), q( x f(y)))
- Per fornire il risultato, dobbiamo conoscere
- la definizione delle funzioni f, g, q
- i valori di x e y
- Come conoscerli?
26SIMBOLI SIGNIFICATO
- Come conoscere il significato di un simbolo?
- o esiste una convenzione diffusa,una cultura
comune, che associa ad un simbolo un preciso
significato - o esiste un ente di riferimento che specifica in
modo esplicito il significato di un simbolo.
27BINDING ENVIRONMENT
- La conoscenza di cosa un simbolo denota viene
espressa da una legame (binding) tra il simbolo e
uno o più attributi. - La collezione dei binding valida in (un certo
punto di) un programma si chiama environment.
28UN ESEMPIO
- Sia f N-gtN f(x)xx
- Sia z 2
- f(z) f(z) vale 8
- f(2) f(y) vale ???
- g(z) vale ???
29SCOPE SCOPE RULES
- Tutte le occorrenze di un nome nel testo di un
programma a cui si applica un dato binding si
dicono essere entro la stessa portata o scope del
binding. - Le regole in base a cui si stabilisce la portata
di un binding si dicono regole di visibilità o
scope rules.
30ESEMPIO
- Sia f N-gtN f(x)xx
- Sia z 2
- f(z) f(z) vale 8
- f(2) f(y) vale ???
- Sia g N-gtN g(x)xx
- g(z) vale 4
- f(g(z)) vale 8
31DEFINIZIONE DI NUOVE FUNZIONI
- Per dare un nome alla nuova funzione,
- il linguaggio deve introdurre costrutti per
estendere un environment - aggiungendo ad esso il nuovo binding che lega il
nome scelto per la funzione allentità che
realizza quella specifica funzione.
32DEFINIZIONE DI NUOVE FUNZIONI
- La definizione di funzione unisce
- la denotazione di una nuova funzione
- lattribuzione di un nome ad essa
- Lenvironment corrente viene arricchito con uno
nuovo binding tra - il nome della funzione, e
- la sua rappresentazione interna
33FUNZIONI IL MODELLO APPLICATIVO
- 1) Valutazione, nellenvironment corrente, del
simbolo che denota il nome della funzione - 2) Valutazione, nellenvironment corrente, delle
espressioni che denotano i parametri - 3) Commutazione allenvironment di definizione
della funzione.
34FUNZIONI IL MODELLO APPLICATIVO
- 4) Chiamata della funzione
- 5) Esecuzione del corpo della funzione (nel suo
environment di definizione) - 6) Restituzione al chiamante di
- controllo
- risultato
- con ripristino dellenvironment esistente al
momento della chiamata.
35LENVIRONMENT
- La definizione di una funzione introduce un
nuovo binding nellenvironment di definizione
della funzione - in C, il global environment
- Al momento dellinvocazione, si crea un nuovo
environment - una struttura che contiene i binding dei
parametri e degli identificatori dichiarati
localmente alla funzione.
36ESEMPIO
- int max (int x, int y )
- return xgty ? x y
-
- Lenvironment corrente viene arricchito di un
nuovo binding max / CodiceDellaFunzione - Quando max viene chiamata, si commuta a un nuovo
environment, in cui sono definite le variabili
intere x e y
37COMUNICAZIONE CLIENTE ? SERVITORE
- Il cliente passa informazioni al servitore
- mediante una serie di parametri attuali.
- Parametri formali
- sono specificati nella dichiarazione del
servitore - esplicitano il contratto fra servitore e cliente
- indicano cosa il servitore si aspetta dal cliente
- Parametri attuali
- sono trasmessi dal cliente allatto della
chiamata - devono corrispondere ai parametri formali in
numero, posizione e tipo
38COMUNICAZIONE CLIENTE ? SERVITORE
- Il cliente passa informazioni al servitore
- mediante una serie di parametri attuali.
- I Parametri attuali sono legati ai parametri
formali al momento della chiamata,in modo
dinamico. - Tale legame
- vale solo per linvocazione corrente
- vale solo per la durata della funzione.
39IL NOSTRO ESEMPIO
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
40IL NOSTRO ESEMPIO
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
1) Valutazione del simbolo znellenvironment
corrente Si trova che z vale 8.
41IL NOSTRO ESEMPIO
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
2) Calcolo dellespressione 2znellenvironment
corrente Si trova che vale 16.
42IL NOSTRO ESEMPIO
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
3) Invocazione della funzione max con parametri
attuali16 e 13. Il controllo passa al servitore.
43IL NOSTRO ESEMPIO
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
4) I parametri formali x e y vengono legati ai
parametriattuali 16 e 13. Inizia lesecuzione
del servitore.
44IL NOSTRO ESEMPIO
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
5) Viene valutata lespressionecondizionale
nellenvironment del servitore. Il risultato è
16.
45IL NOSTRO ESEMPIO
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
6) Il valore così determinato (16)viene
restituito al cliente. Il servitore termina e il
controllo torna al cliente.
46IL NOSTRO ESEMPIO
7) Il valore restituito (16) viene usato per
inizializzare lavariabile m (nellenvironment
del cliente)
- Il servitore...
- int max (int x, int y )
- return xgty ? x y
-
- e un possibile cliente
- main()
- int z 8
- int m max(2z,13)
-
47RIASSUNTO
- Allatto dellinvocazione di una funzione
- si crea una nuova attivazione (istanza) del
servitore - si alloca la memoria per i parametri (e le
eventuali variabili locali) - si trasferiscono i parametri al servitore
- si trasferisce il controllo al servitore
- si esegue il codice della funzione.
48PASSAGGIO DEI PARAMETRI
- In generale, un parametro può essere
- trasferito
- per valore o copia (by value)
- si trasferisce il valore del parametro attuale
- per riferimento (by reference)
- si trasferisce un riferimento al parametro attuale
49PASSAGGIO PER VALORE
- si trasferisce una copia del valore del parametro
attuale
z
45
cliente
50PASSAGGIO PER VALORE
- si trasferisce una copia del valore del parametro
attuale
valore (copiato) di z
copia
z
45
w
45
istanza del servitore
cliente
servitore
51PASSAGGIO PER VALORE
Ogni azione fatta su w è strettamente locale al
servitore
- si trasferisce una copia del valore del parametro
attuale
valore (copiato) di z
copia
z
45
w
45
istanza del servitore
cliente
servitore
52PASSAGGIO PER RIFERIMENTO
- si trasferisce un riferimento al parametro attuale
z
45
cliente
53PASSAGGIO PER RIFERIMENTO
- si trasferisce un riferimento al parametro attuale
riferimento a z (indirizzo)
?
riferimento
z
45
w
?
istanza del servitore
cliente
servitore
54PASSAGGIO PER RIFERIMENTO
Ogni azione fatta su w è in realtà fatta
sulla variabile z del cliente!
- si trasferisce un riferimento al parametro attuale
riferimento a z (indirizzo)
?
riferimento
z
45
w
?
istanza del servitore
cliente
servitore
55PASSAGGIO DEI PARAMETRI IN C
- In C, i parametri sono trasferiti sempre e solo
- per valore (by value)
- si trasferisce una copia del parametro attuale,
non loriginale! - tale copia è strettamente privata e locale a quel
servitore - il servitore potrebbe quindi alterare il valore
ricevuto, senza che ciò abbia alcun impatto sul
cliente
56PASSAGGIO DEI PARAMETRI IN C
- In C, i parametri sono trasferiti sempre e solo
- per valore (by value)
- Conseguenza
- è impossibile usare un parametro per trasferire
informazioni verso il cliente - per trasferire (una) informazione al cliente si
sfrutta il valore di ritorno della funzione
57ESEMPIO VALORE ASSOLUTO
- Definizione formale
- x N ? N
- x vale x se x ? 0
- x vale -x se x ? 0
- Codifica sotto forma di funzione C
- int valAss(int x)
- return (xlt0) ? -x x
58ESEMPIO VALORE ASSOLUTO
- Servitore Cliente
- int valAss(int x) return (xlt0) ? -x x
-
- main()
- int z -87
- int absz valAss(z)
- int abs4 valAss(4)
-
59ESEMPIO VALORE ASSOLUTO
Quando valAss(z) viene chiamata, il valore
attuale di z, valutato nel- lenvironment
corrente (-87), viene copiato e passato a valAss.
- Servitore Cliente
- int valAss(int x) return (xlt0) ? -x x
-
- main()
- int z -87
- int absz valAss(z)
- int abs4 valAss(4)
-
60ESEMPIO VALORE ASSOLUTO
- Servitore Cliente
- int valAss(int x) return (xlt0) ? -x x
-
- main()
- int z -87
- int absz valAss(z)
- int abs4 valAss(4)
-
valAss riceve quindi una copia del valore -87 e
la lega al simbolo x. Poi si valuta
lespressione, che qui vale 87, e si restituisce
questo valore.
61ESEMPIO VALORE ASSOLUTO
- Servitore Cliente
- int valAss(int x) return (xlt0) ? -x x
-
- main()
- int z -87
- int absz valAss(z)
- int abs4 valAss(4)
-
Il valore restituito (87) viene usato per
inizializzare la variabile absz.
62ESEMPIO MASSIMO DI DUE NUMERI
- Definizione formale
- max N ? N ? N
- max(x,y) vale x se x ? y
- max(x,y) vale y se x lt y
- Codifica sotto forma di funzione C
- int max(int x, int y)
- return (xlty) ? y x
63ESEMPIO MASSIMO DI DUE NUMERI
- Servitore Cliente
- int max(int x, int y) return (xlty) ? y x
-
- main()
- int z -87, y 12
- int m max(z,18)
- int n max(4y,z100)
-
64ESEMPIO MASSIMO DI DUE NUMERI
Si valutano le due espressioni che costituiscono
i parametri attuali (nel- lenvironment del main)
e si trasmette alla funzione copia dei valori
ottenuti.
- Servitore Cliente
- int max(int x, int y) return (xlty) ? y x
-
- main()
- int z -87, y 12
- int m max(z,18)
- int n max(4y,z100)
-
65ESEMPIO MASSIMO DI DUE NUMERI
- Servitore Cliente
- int max(int x, int y) return (xlty) ? y x
-
- main()
- int z -87, y 12
- int m max(z,18)
- int n max(4y,z100)
-
La funzione riceve copia dei valori -87 e 18, e
li lega ai simboli x e y. Poi si valuta
lespressione. Il risultato (18) è restituito al
main chiamante.
66PASSAGGIO DEI PARAMETRI IN C
- Perché il C adotta sempre e solo il passaggio
- per valore (by value)?
- è sicuro le variabili del chiamante e del
chiamato sono completamente disac-coppiate - consente di ragionare per componenti e servizi
la struttura interna dei singoli componenti è
irrilevante
67PASSAGGIO DEI PARAMETRI IN C
- Limiti
- consente di restituire al cliente solo valori di
tipo (relativamente) semplice - non consente di restituire collezioni di valori
- non consente di scrivere componenti software il
cui scopo sia diverso dal calcolo di una
espressione
68PASSAGGIO DEI PARAMETRI
- Molti linguaggi mettono a disposizione il
- passaggio per riferimento (by reference)
- non si trasferisce una copia del valore del
parametro attuale - si trasferisce un riferimento al parametro, in
modo da dare al servitore accesso di- retto al
parametro in possesso del cliente - il servitore accede e modifica direttamente il
dato del cliente.
69PASSAGGIO DEI PARAMETRI IN C
- Il C non supporta direttamente il passaggio
- per riferimento
- è una grave mancanza!
- il C lo fornisce indirettamente solo per alcuni
tipi di dati - ergo, occorre costruirselo quando serve.(vedremo
dei casi) - Il C e Java invece lo forniscono.
70DEFINIZIONE DI NUOVE FUNZIONI STRATEGIE DI
COMPOSIZIONE
- La capacità di definire nuove funzioni
- permette
- di definire nuove operazioni
- di introdurre variabili per denotare i dati in
modo simbolico - di esprimere la ripetizione di una espressione
per un numero (prefissatoo meno) di volte.
71STRATEGIE DI COMPOSIZIONE
- Tre grandi approcci
- 1) la composizione di funzioni
- 2) le espressioni condizionali
- 3) la ricorsione.
-
- Le funzioni definibili in termini di un insieme
- prescelto di primitive e delle precedenti
- strategie di composizione costituiscono un
- insieme detto delle funzioni ricorsive generali.
721) COMPOSIZIONE DI FUNZIONI
- I parametri in una chiamata di funzione pos-
- sono consistere/comprendere altre funzioni
- Es f(x) g(f(x), q(x f(y)))
- x1 f(x)
- x2 f(x) (mossa evitabile da un automa
intelligente) - x3 f(y)
- x4 x x3
- x5 q( x4 )
- x6 g( x2,x5 )
- x7 x1 x6
732) ESPRESSIONE CONDIZIONALE
- Lespressione condizionale riflette la
consuetudine matematica di definire le funzioni
per elencazione di casi. - Esempio
- abs N -gt N
- abs(x) vale x se x ? 0
- abs(x) vale -x se x ? 0
743) LA RICORSIONE
- La ricorsione consiste nella pos-sibilità di
definire una funzione in termini di se stessa. - È basata sul principio di induzione matematica
- se una proprietà P vale per nn0
- e si può provare che, assumendola valida per n,
allora vale per n1 - allora P vale per ogni n?n0
75LA RICORSIONE
- Operativamente, risolvere un problema con un
approccio ricorsivo comporta - di identificare un caso base la cui soluzione
sia ovvia - di riuscire a esprimere la soluzione al caso
generico n in termini dello stesso problema in
uno o più casi più semplici (n-1, n-2, etc).
76LA RICORSIONE ESEMPIO
Esempio ! N ? N n! vale 1 se n ? 0 n! vale
n(n-1)! se n gt 0 Codifica int fact(int n)
return n0 ? 1 nfact(n-1)
77LA RICORSIONE ESEMPIO
Attenzione la codifica non corrisponde alla
specifica!! Il 2 caso si applica per n?0,cioè
anche per nlt0 !!MA COSÌ PUÒ NON TERMINARE!
Esempio ! N ? N n! vale 1 se n ? 0 n! vale
n(n-1)! se n gt 0 Codifica int fact(int n)
return n0 ? 1 nfact(n-1)
78LA RICORSIONE ESEMPIO
Esempio ! N ? N n! vale 1 se n ? 0 n! vale
n(n-1)! se n gt 0 Codifica int fact(int n)
/ return n0 ? 1 nfact(n-1) / return ngt0
? nfact(n-1) 1
Nuova codifica
79ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
80ESEMPIO FATTORIALE
Si valuta lespressione che costituisce
il parametro attuale (nellenvironment del main)
e si trasmette alla funzione fatt una copia del
valore così ottenuto (7).
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
81ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
La funzione riceve una copia del valore 7 e la
lega al simbolo n. Poi valuta lespres- sione
condizionale ciò impone di valutare una
espressione che contiene una nuova chiamata di
funzione.
82ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
Si valuta quindi, nellenvironment di
fatt, lespressione n-1 (che vale 6), e si
effettua una nuova chiamata al servitore fatt,
pas- sandogli una copia del valore 6.
83ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
Il (nuovo) servitore riceve quindi una copia del
valore 6 e, come sopra, valuta lespres- sione
condizionale. Ciò lo porta a dover fare una nuova
chiamata passando 5.
84ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
la cosa prosegue, servitore dopo
servitore.. ...
85ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
Prima o poi, dato che il valore passato cala ogni
volta, si giunge a invocare fatt con parametro 1.
In questo caso, la valutazione dellespressione
dà come risultato 1.
86ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
Ciò chiude la sequenza di chiamate ricorsive. Il
controllo torna al servitore precedente, che può
finalmente valutare lespressione n1 (valutando
n nel suo environment, dove vale 2) ottenendo 2.
87ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
Il valore 2 viene restituito al servitore
pre- cedente, che a sua volta può così
valutare lespressione n2 (valutando n nel suo
environment, dove vale 3) ottenendo 6.
88ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
la cosa prosegue ...
89ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
Prima o poi, a forza di retrocedere, si torna al
primo servitore attivato, che può quindi valutare
lespressione n720 (valutando n nel suo
environment, dove vale 7), giun- gendo così a
trovare il valore 5040.
90ESEMPIO FATTORIALE
- Servitore Cliente
- int fatt(int n) return (ngt0) ? nfatt(n-1)
1 -
- main()
- int z 5
- int fz fatt(z2)
- int f6 fatt(6)
-
Il valore 5040, restituito dal servitore fatt,
può quindi essere usato per inizializzare la
variabile fz.
91UN ALTRO ESEMPIO
- Problema
- calcolare la somma dei primi N interi
- Specifica
- Considera la somma (123...(N-1)N come
- composta di due termini
- (123...(N-1))
- N
- Esiste un caso banale assolutamente ovvio
- la somma fino a 1 vale 1.
92UN ALTRO ESEMPIO
Il primo termine non è altro che la soluzione
allo stesso problema inun caso più semplice
- Problema
- calcolare la somma dei primi N interi
- Specifica
- Considera la somma (123...(N-1)N come
- composta di due termini
- (123...(N-1))
- N
- Esiste un caso banale assolutamente ovvio
- la somma fino a 1 vale 1.
Il secondo termine è un valore già noto.
93UN ALTRO ESEMPIO
Problema calcolare la somma dei primi N
interi Codifica int sommaFinoA(int n) return
(n1) ? 1 sommaFinoA(n-1) n
94UN TERZO ESEMPIO
Problema calcolare lN-esimo numero di Fibonacci
95UN TERZO ESEMPIO
Problema calcolare lN-esimo numero di
Fibonacci Codifica unsigned fibonacci(unsigned
n) return (nlt2) n ? fibonacci(n-1)
fibonacci(n-2)
96UN TERZO ESEMPIO
Ricorsione non lineare ogniinvocazione del
servitore causadue nuove chiamate al servitore
medesimo.
Problema calcolare lN-esimo numero di
Fibonacci Codifica unsigned fibonacci(unsigned
n) return (nlt2) n ? fibonacci(n-1)
fibonacci(n-2)
97UNA RIFLESSIONE
- Negli esempi di ricorsione visti finora
- fattoriale
- somma dei primi N interi
- calcolo dellN-esimo numero di Fibonacci
- si inizia a sintetizzare il risultato solo dopo
che si sono aperte tutte le chiamate, a
ritroso, mentre le chiamate si chiudono.
98UNA RIFLESSIONE
- Le chiamate ricorsive decompongono via via il
problema, ma non calcolano nulla - Il risultato viene sintetizzato a partire dalla
fine, perché prima occorre arrivare al caso
banale - il caso banale fornisce il valore di partenza
- poi, e solo poi, si sintetizzano, a ritroso, i
successivi risultati parziali.
99UNA RIFLESSIONE
- Ciò indica che tali soluzioni
- sono sintatticamente ricorsive
- e danno luogo a un processo computa-zionale
effettivamente ricorsivo.
100UN ESEMPIO DIVERSO
Problema trovare il Massimo Comun Divisore tra N
e M
101UN ESEMPIO DIVERSO
Problema calcolare il Massimo Comun Divisore tra
N e M Codifica int mcd(int m, int n) return
(mn) m ? (mgtn) ? mcd(m-n, n) mcd(m,
n-m)
102UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
103UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Si valutano i parametri attuali e si invoca la
funzione con parametri 36 e 15
104UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Si legano i parametri 36 e 15 ai
parametri formali m e n, e si valuta
lespressione condizionale.
105UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Poiché 36 ? 15, si invoca nuovamente la funzione
con parametri m-n (21) e n (15).
106UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Il nuovo servitore, poiché 21 ? 15, fa la stessa
cosa e invoca nuovamente la funzione con
parametri m-n (6) e n (15).
107UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Il nuovo servitore, poiché 6 ? 15, invoca un
ulteriore servitore con parametri m (6) e n-m
(9).
108UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Poiché 6 ? 9, si ha una nuova chiamata con
parametri m (6) e n-m (3).
109UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Poiché 6 ? 3, si ha una nuova invocazione (lultim
a!) con parametri m-n (3) e n (3).
110UN ESEMPIO DIVERSO
- Servitore Cliente
- int mcd(int m, int n) return (mn) m ?
(mgtn) ? mcd(m-n, n) mcd(m, n-m) - main()
- int m mcd(36,15)
-
Poiché 3 3, il servitore termina e restituisce
come risultato 3.
111UN ESEMPIO DIVERSO
- Perché questo esempio è diverso ?
- il risultato viene sintetizzato via via che le
chiamate si aprono, in avanti - quando le chiamate si chiudono non si fa altro
che riportare indietro, fino al cliente, il
risultato ottenuto.
112UNA RIFLESSIONE
- La soluzione ricorsiva individuata per lMCD è
sintatticamente ricorsiva... - ma dà luogo a un processo computa-zionale
diverso dal precedente - un processo computazionale ITERATIVO
- Il risultato viene sintetizzato in avanti
- ogni passo decompone e calcola
- e porta in avanti il nuovo risultato parziale
113UNA RIFLESSIONE
- Ogni processo computazionale ITERATIVO
- calcola a ogni passo un risultato parziale
- dopo k passi, si ha a disposizione il risultato
parziale relativo al caso k - questo non è vero nei processi computa-zionali
ricorsivi - là, finché non si sono aperte tutte le chiamate,
non è disponibile nessun risultato!
114RICORSIONE TAIL
- Una ricorsione che realizza un processo
- computazionale ITERATIVO
- è una ricorsione solo apparente
- la chiamata ricorsiva è sempre lultima
istruzione - i calcoli sono fatti prima
- la chiamata serve solo, dopo averli fatti, per
proseguire la computazione - questa forma di ricorsione si chiama RICORSIONE
TAIL (ricorsione in coda)