Lezione 1 - Imperativo o procedurale
Corso — Programmazione
Linguaggi di programmazione— Paradigmi di programmazione
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Paradigmi di programmazione
• Un paradigma di programmazione è un modello
concettuale che fornisce la “struttura” di un programma.
• I principali paradigmi di programmazione sono:
Programmazione
Programmazione
Programmazione
Programmazione
imperativa o procedurale
funzionale
logica
orientata agli oggetti
Paradigma imperativo o procedurale(1)
• Programmazione imperativa: Sono linguaggi ``action
oriented'' ovvero la computazione è vista come una
sequenza di azioni.
• Un programma è composto da istruzioni che realizzano
trasformazioni di stato.
• Uno stato è identificato da tutti i valori di un certo insieme
di variabili in un certo stadio dell'esecuzione.
• Esempi C, Pascal etc.
• E' il paradigma che abbiamo usato fino ad ora
Paradigma imperativo o procedurale(2)
• L' assegnazione è l'elemento fondamentale
• Il programma che scriviamo non è la stessa cosa della
computazione che avviene (elementi strutturati e
invarianti)
• Rapporto tra programma statico ed esecuzione dinamica
• Invarianti e blocchi strutturati
• Invarianti servono soprattutto per pensare al programma
non solo per valutarne la correttezza a posteriori
Paradigma imperativo o procedurale:
esempio
• Esempio di problema affrontato con la programmazione
imperativa
• Consideriamo il problema della ricerca lineare in un array.
• La ricerca lineare prevede di scorrere tutto l'array e di
fermarsi se trovo l'elemento
• Quindi ho due test per determinare quando il programma
si arresta
• Provate a scrivere lo pseudocodice relativo avrete diverse
possibilità contenenti due test
[esempio]
while (esistono altri elementi da valutare) do
if (elemento trovato in posizione i) then return i
else considera l'elemento successivo
endwhile
return (0) element not found
Paradigma imperativo o procedurale(4)
• Il fatto di strutturare diversamente i dati (array) permette
di usare invarianti differenti
• Di conseguenza permette di sviluppare programmi
differenti
• Approccio con sentinella: considero l'array con elementi
che partono dal secondo elemento mentre nel primo
metto l'elemento da cercare
[esempio con sentinella]
A[0]=x; i=n;
while x<>A[i] do
i=i-1
endwhile
return (i)
Lezione 2 - Funzionale parte I
Corso — Programmazione
Linguaggi di programmazione— Paradigmi di programmazione
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Programmazione funzionale(1)
• Ha le sue radici nel lambda calcolo che Alonso Church ha
inventato negli anni 30
• Un programma è una funzione che viene valutata per
ottenere un risultato
• Il principio della programmazione funzionale pura è: ``il
valore di una espressione dipende solamente dai valori
delle sue sub-espressioni, se ne esistono''
• Quindi gli assegnamenti non sono considerati, dato che
possono cambiare valori alle variabili
• La programmazione funzionale pura è una
programmazione senza assegnamenti
• Non si considerano le tecniche di salvataggio dei valori
della macchina sottostante
• I cambi del valore di una variabile durante la valutazione
di una espressione sono considerati come degli ``side
effect''
• Esempi storici ML, Lisp, Scheme etc.
Programmazione funzionale(2)
• La potenza di questo paradigma stà nell'uso diretto di
funzioni e ricorsione
• Gestione dell'allocazione implicita
• Storage allocato se serve e deallocato se non serve più
(garbage collection)
• Funzioni come ``first-class values''. Le funzioni hanno lo
stesso status di ogni altro valore
• Una funzione può essere il valore di una espressione, può
essere passata come argomento e può essere messa in
una struttura dati o in una variabile, può essere restituita
come valore di ritorno da altre funzioni
Programmazione funzionale(2)
• Le funzioni possono avere dei nomi, come in ogni altro
linguaggio, o essere definite anonimamente (a volte
anche a run-time)
• Si basa sulle computazione di espressioni
log n: funzione logaritmica applicata a n
2+4: funzione + applicata a 2 e 4
Massimo tra x e y: if (x > y) then x else y (espressioni
contenenti condizioni e definizione di funzioni)
Programmazione funzionale vs imperativa
• Il punto di forza della programmazione funzionale è a
mancanza di effetti collaterali delle funzioni
• Si ha una migliore verifica del codice e migliore
ottimizzazione
• Nella programmazione imperativa avviene il cambio dello
stato del programma attraverso assegnazioni
• Nella programmazione funzionale i valori non vengono
calcolati cambiando lo stato del programma ma
costruendo nuovi stati a partire dai precedenti
• Vedremo un esempio famoso per chiarire questo tipo di
concetto
• Non può per definizione dare luogo a bug a run-time. Al
momento della compilazione o della prima esecuzione o
funziona o non funziona (non esistono eccezioni)
Effetti collaterali di una funzione
• Una funzione ha un effetto collaterale quando modifica un
valore o uno stato al di fuori del proprio scopo
• Esempio: se modifico una variabile globale o una statica,
quando modifico il valore di un argomento, o scrivo su un
file o chiamo funzioni con effetti collaterali
• La programmazione imperativa vive degli effetti collaterali
delle funzioni
• La programmazione funzionale tende a limitarli (più
difficili le operazioni di input output)
Trasparenza referenziale(1)
• La trasparenza referenziale significa che una espressione
(anche una funzione quindi) può essere sostituita con il
suo valore
• Se considero la funzione f(sqr(2),sqr(2)) allora posso
evitare di calcolare due volta sqr(2) se ho la trasparenza
referenziale
• Per avere la trasparenza referenziale una funzione deve
essere senza effetti collaterali e deve essere puramente
funzionale (restituire sempre lo stesso output a fronte
degli stessi input)
Trasparenza referenziale(2)
• A volte si parla anche di high order functions quando una
funzione prende una o più funzioni come input e da come
output una funzione
• Esempio f(x)= x+4, la funzione high order doppia è
definita come: doppia(f, 8) = f(f(8)) = (8 + 4) + 4
• In programmazione imperativa è possibile fare qualche
cosa si analogo però sfruttando delle specifiche
caratteristiche del linguaggio
• Esempio in C si può passare un puntatore ad una funzione
come parametro
Lezione 3 - Logico e orientato agli oggetti
Corso — Programmazione
Linguaggi di programmazione— Paradigmi di programmazione
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Linguaggi dichiarativi e procedurali
• Procedurali: istruzioni che indicano al calcolatore come
svolgere un determinato compito. Dati - istruzioni risultato
• Dichiarativi: indicano cosa deve essere fatto ma non
come. Lasciano al calcolatore la scelta del come farlo
Programmazione logica(1)
• Descrivere la conoscenza che si ha sul problema piuttosto
che il procedimento che genera la sua soluzione
• Occorre rappresentare bene le entità in gioco in relazione
all'applicazione usando un linguaggio logico
• Il problema è descritto da oggetti o entità, da relazioni tra
loro e da proposizioni che esprimono proprietà logiche
sulle relazioni
• Problema descritto come un insieme di formule logiche
• Sfrutta un linguaggio di natura dichiarativa
• Un programma in questo paradigma è un insieme di fatti e
regole e la sua esecuzione equivale alla realizzazione di
una dimostrazione (deduzione).
• Si forniscono i fatti (informazioni vere) le regole che
compongono i fatti o risultati di altre regole
• Si interroga il programma per trovare la soluzione
Programmazione logica(2)
• Programmazione classica: Algoritmi + Strutture dati =
Programmi
Dipendenza tra dati e algoritmo
• Programmazione logica: Algoritmo = Logica(fatti +
regole) + Controllo (risoluzione)
Dati e controllo indipendenti
• La programmazione logica viene di solito affiancata allo
studio del linguaggio Prolog
Programmazione logica(3)
Fatti:
Every psychiatrist is a person.
Every person he analyzes is sick.
Jacques is a psychiatrist in Marseille.
Interrogazioni:
Is Jacques a person?
Where is Jacques?
Is Jacques sick?
Fondamenti della programmazione ad
oggetti: Raggruppare dati e operazioni
• Scomposizione di problemi in sottoproblemi
• Astrazione: procedurale, modulare, dei dati, di oggetti
• Astrazione procedurale: abbiamo già visto è una delle
prime ad essere state applicate. Permette di concentrarsi
su una sezione del codice alla volta
• Astrazione modulare: è stata sfruttata per molto tempo
prima di concretizzarsi in un paradigma di
programmazione. Abbiamo visto le basi della modularità
associata alla progettazione.
Collezione di dati e procedure che agiscono sui dati. E'
meglio organizzare moduli attorno ai dati che attorno alle
azioni sui dati (astrazione dei dati)
• Astrazione dei dati: è un tipo definito dal
programmatore (stack, albero ecc.).
• Astrazione degli oggetti: è il paradigma di
programmazione orientato agli oggetti
Linguaggio e astrazione
• Supporto del linguaggio: L'astrazione richiede che il
linguaggio di programmazione permetta di nascondere
delle informazioni rendendo il programma più semplice da
leggere
• Un linguaggio supporta uno stile di programmazione se lo
stile può essere espresso, controllato ed implementato in
modo efficiente
• Un linguaggio permette uno stile di programmazione se
posso con qualche trucco arrivare a programmare con i
dettami dello stile ma non ho il pieno supporto del
linguaggio
• La possibilità di nascondere informazioni supporta varie
forme di astrazione e di solito si realizza con la definizione
della visibilità dei nomi
• Alcuni linguaggi supportano nativamente la modularità
come ad esempio il Pascal (unit - interface implementation)
Astrazione procedurale
• Nel momento in cui una procedura è stata definita, la sua
implementazione può essere astratta (non importa più il
suo corpo ma quello che fa e l'interfaccia).
• Comportamento di una procedura: cosa fa vista dal di
fuori
• Implementazione di una procedura: nasconde i
dettagli implementativi di come il comportamento è
ottenuto
• Prendiamo ad esempio un parser che fa anche la
valutazione. Sappiamo che è costituito da uno scanner
(analisi lessicale e divisione in token) e da un parser con
valutazione (valutazione grammaticale e del valore
semantico)
• Il dividere in procedure aiuta la progettazione, i moduli
sono ancora più utili dato che scanner e parser lavorano
su dei dati
Astrazione modulare
• Un modulo è una collezione di dichiarazioni che includono
variabili e procedure
• Il modulo agisce come una black-box con cui il resto del
programma interagisce attraverso la sua interfaccia
• Una interfaccia è un sottoinsieme delle dichiarazioni del
modulo
• Le interfacce e le implementazioni del modulo possono
considerarsi private o pubbliche
• Ruolo: modulo organizzato attorno ai dati. Il ruolo è
generale non specifico di procedure che sono
implementate nel modulo
• Interfaccia: se il ruolo è chiaro si definisce meglio la sua
interfaccia. Le procedure di interfaccia determinano il
comportamento del modulo per il resto del programma
• Implementazione: Nasconde nelle parti private del
modulo le decisioni (variabili e procedure) che non sono di
interesse per il resto del programma
Tipi - classi - oggetti
• Il programma manipola dei tipi strutturati
• Una classe corrisponde ad uno di questi tipi
• La classe è l'abbreviazione di classe di oggetti
• Un oggetto è una entità che vive a run-time con dei dati
istanziati su cui le operazioni possono agire
• Uno stack è un oggetto i cui dati corrispondono con il
contenuto della stack stesso
Procedure - moduli - classi
• Servono a bisogni differenti e possono essere usati in
combinazione
• Procedure: sono richieste per implementare una
operazione di un modulo o di una classe
• Modulo: può essere usato per partizionare staticamente
il codice di un programma organizzato in classi
• Le differenze non sono nelle attività ma in come sono
organizzate
• Procedure: Definiscono ogni dettaglio ogni
rappresentazione è nota tramite il programma.
• Moduli: Nasconde la rappresentazione, esponendo le
operazioni pubbliche. Il vantaggio rispetto alla procedura
è che la rappresentazione è nascosta e l'accesso è
controllato.
• Classi: Come per i moduli la rappresentazione è nascosta
l'accesso è controllato. Gli oggetti vengono inizializzati
alla creazione
Classe ed eliminazione dei doppi(1)
• Rivediamo l'esempio dell'algoritmo della eliminazione dei
doppi considerando come elementi da confrontare delle
istanze di una classe Entry così definita:
Class Entry
procedure read();
procedure write();
function endmarker():boolean;
function equal(Entry):boolean;
function copy(Entry):boolean;
constructor Entry;
destructor Entry;
Classe ed eliminazione dei doppi(2)
Entry a,b;
a.read();
while not a.endmarker() do
a.write();
do
b.read;
while a.equal(b)
a.copy(b)
endwhile
Programmazione orientata agli oggetti
• Approccio che si integra con quello procedurale ma la
progettazione è radicalmente differente
• Un programma è un insieme di oggetti (astrazioni della
realtà) dotati di proprietà (dati) e metodi (procedure) che
comunicano tramite scambio di messaggi.
• E' un paradigma tanto importante da essere stato
adottato da molti dei linguaggi più recenti che ibridano
diversi paradigmi
• Javascript: OO e funzionale, Ruby fortemente OO
(aggiungere e modificare metodi a run-time) e funzionale
• Python OO e funzionale, molto usato in scripting
• Uno tra i più usati linguaggi di programmazione ad oggetti
prima dell'avvento di Java è stato C++ che poteva essere
usato per scrivere in modalità procedurale o ad oggetti