Esercizio: punti e segmenti ! Punti e segmenti nel piano, con data abstraction Carlo Strapparava - Informatica Esercizio: punti e segmenti ! Punti e segmenti nel piano, con data abstraction ! Lunghezza di un segmento l = (x 2 " x1 ) 2 + (y 2 " y1 ) 2 y2 ! Data abstraction: ! Segmento ! y1 " " Costruttore make-seg pt1 pt2 Selettori start-point seg end-point seg ! Punto " x1 x2 " Costruttore make-point x y Selettori x-coor point y-coor point Carlo Strapparava - Informatica 1 Esercizio: punti e segmenti (define (segment-length segment) (let ((dx (- (x-coord (end-point segment)) (x-coord (start-point segment)))) (dy (- (y-coord (end-point segment)) (y-coord (start-point segment))))) (sqrt (+ (square dx) (square dy))))) Implementazione segmento Implementazione punto (coordinate rettangolari) (define (make-seg pt1 pt2) (cons pt1 pt2)) (define (make-point x y) (cons x y)) (define (start-point seg) (car seg)) (define (x-coor point) (car point)) (define (end-point seg) (cdr seg)) (define (y-coor point) (cdr point)) Carlo Strapparava - Informatica Esercizio: punti e segmenti ! Cambiamo la rappresentazione dei punti e usiamo la rappresentazione polare p=(r,!) ! I programmi di alto livello (es. segment-length) non cambiano: usano costruttori e selettori con gli stessi nomi x = r cos" y = r sin " (define (make-point r ang) (cons r ang)) r ! ! (define (x-coor p) (* (car p) (cos (cdr p)))) (define (y-coor p) (* (car p) (sin (cdr p)))) Carlo Strapparava - Informatica 2 Che cosa intendiamo per “dati” ? ! I dati sono definiti da una collezione di costruttori e selettori, insieme a specifiche condizioni che queste procedure devono soddisfare ! Data abstraction interviene a tutti i livelli ! Es. Non abbiamo mai detto cosa sia una coppia, ma soltanto che avevamo le procedure cons, car e cdr per operare sulle coppie Carlo Strapparava - Informatica Che cosa intendiamo per “dati” ? ! Riguardo le coppie, l’unica cosa che ci interessa sapere è che (car (cons x y)) => x (cdr (cons x y)) => y ! cons, car, e cdr sono primitive nello Scheme ! Tuttavia qualunque tripla di procedure che soddisfa le precedenti condizioni, può essere usata per implementare le coppie Carlo Strapparava - Informatica 3 Che cosa intendiamo per “dati” ? ! Per esempio, possiamo implementare le coppie, senza usare nessuna struttura dati, ma soltanto le procedure (define (cons x y) (lambda (pick) (cond ((= pick 1) x) ((= pick 2) y) (else (error "L'argomento non e' ne' 1 ne' 2”)))) ) (define (car z) (z 1)) (define (cdr z) (z 2)) Carlo Strapparava - Informatica Che cosa intendiamo per “dati” ? (define (cons x y) (lambda (pick) (cond ((= pick 1) x) ((= pick 2) y) (else (error "L'argomento non e' ne' 1 ne' 2”)))) ) (define (car z) (z 1)) (define (cdr z) (z 2)) (cons 6 9) => (lambda (pick) (cond ((= pick 1) 6) ((= pick 2) 9) (else (error "L'argomento non e' ne' 1 ne' 2”)))) Carlo Strapparava - Informatica 4 Cons, car, cdr in versione procedurale ! Esiste una versione ancora più elegante di implementare le coppie “proceduralmente” (define (cons x y) (lambda (m) (m x y))) (define (car z) (z (lambda (p q) p))) Esercizio: verificare che funzionano con il modello di sostituzione (define (cdr z) (z (lambda (p q) q))) Carlo Strapparava - Informatica Che cosa intendiamo per “dati” ? ! L’uso di queste procedure appena viste è quanto di ! ! ! ! più lontano ci sia dalla nostra intuizione di dato Tuttavia possiamo verificare che soddisfano le condizioni date per cons, car e cdr Se usiamo queste procedure, esse sono indistinguibili da quelle che usano strutture dati “reali” La rappresentazione procedurale dei dati gioca un ruolo fondamentale nelle techniche di programmazione avanzata, come l’object-oriented In particolare quanto visto prima, è un esempio di object-oriented di stile message-passing Carlo Strapparava - Informatica 5 Visualizzare le coppie ! Abbiamo visto che le coppie (pairs) costituiscono una sorta di “colla” per costruire oggetti composti complessi ! La notazione “standard” per visualizzare le coppie - ad es. (cons 1 2) - è chiamata notazione box-and-pointer 2 (cons 1 2) 1 (car (cons 1 2)) " 1 (cdr (cons 1 2)) " 2 Carlo Strapparava - Informatica Dati gerarchici e proprietà di chiusura ! Abbiamo visto che cons può essere usato per combinare coppie ! Le coppie costituiscono una sorta di mattone universale per costruire ogni sorta di strutture dati (cons (cons 1 2) (cons 3 4)) 3 4 1 2 Carlo Strapparava - Informatica 6 Dati gerarchici e proprietà di chiusura 4 (cons (cons 1 (cons 2 3)) 4)) 1 2 3 ! La capacità di creare coppie i cui elementi sono altre coppie è l’essenza dell’importanza della struttura a lista ! Questa capacità si chiama proprietà di chiusura del cons ! cons può prendere coppie in input e produce coppie in output Carlo Strapparava - Informatica Proprietà di chiusura ! La parola “chiusura” viene dall’algebra astratta ! Un insieme di elementi si dice chiuso secondo una certa operazione, se applicando l’operazione agli elementi dell’insieme, si ottengono elementi che appartengono ancora all’insieme Carlo Strapparava - Informatica 7 Proprietà di chiusura ! La proprietà di chiusura ci permette di creare ! ! ! ! strutture gerarchiche Strutture gerarchiche: strutture composte di parti che a loro volta sono composte di parti ecc… Le procedure composte sono ancora procedure I dati composti sono ancora dati Vedremo alcune tecniche standard per rappresentare sequenze (liste) e alberi, usando le coppie Carlo Strapparava - Informatica Rappresentare le sequenze (liste) ! Una sequenza è una collezione ordinata di oggetti ! Un modo semplice di rappresentare le sequenze in termini di coppie è usando una catena di coppie (cons 1 (cons 2 (cons 3 (cons 4 nil)))) 1 2 3 4 Carlo Strapparava - Informatica 8 Rappresentare le sequenze (liste) ! Il car di ciascuna coppia corrisponde ad un elemento della catena ! Il cdr di una coppia è la coppia successiva nella catena ! Il cdr della coppia finale segnala la fine della catena: " " " nella rappresentazione box-and-pointer è indicato come un barra / nei programmi con la variabile nil nil può essere pensato come la sequanza di nessun elemento (cioè la lista vuota) Carlo Strapparava - Informatica Liste ! Lo Scheme fornisce una procedura primitiva list che è il costruttore delle liste ! La lista vista prima può essere costruita con (list 1 2 3 4) ! In generale (list <el1> <el2> … <eln>) ! È equivalente a (cons <el1> (cons <el2> (cons … (cons <eln> nil)…))) ! (list) ritorna la lista vuota: (define nil (list)) ! I sistemi Scheme stampano le liste come sequenze di elementi (list 1 2 3 4) " (1 2 3 4) Carlo Strapparava - Informatica 9 Operazioni sulle liste ! Tramite car e cdr possiamo scrivere ! procedure che manipolano le liste Per esempio, scriviamo una procedura list-ref che prende due argomenti: 1. 2. una lista un numero n ! e ritorna l’ n-esimo elemento della lista ! Il primo elemento è in posizione 0 Carlo Strapparava - Informatica Operazioni sulle liste (define (list-ref items n) (if (= n 0) (car items) ;per n=0 torna il car della lista (list-ref (cdr items) (- n 1)))) ;altrimenti torna l’ (n-1) esimo elemento del cdr della lista 3 2 1 0 (define lista-quadrati (list 1 4 9 16 25)) (list-ref lista-quadrati 3) "16 Carlo Strapparava - Informatica 10 Operazioni sulle liste ! Spesso dobbiamo scandire la lista tramite il cdr ! Lo Scheme fornisce una procedura primitiva null? che testa se il suo argomento è la lista vuota (null? nil) " #t (null? (list 1 2)) " #f Carlo Strapparava - Informatica Esempio: lunghezza di una lista (define (length items) (if (null? items) 0 ;la lunghezza della lista vuota è 0 (+ 1 (length (cdr items))))) ;altrimenti la lunghezza è 1 più la lunghezza del cdr (define dispari (list 1 3 5 7)) (length dispari) " 4 Carlo Strapparava - Informatica 11 Esempio: lunghezza di una lista ! Riconosciamo nella definizione di length il classico piano dell’induzione " " la lunghezza della lista vuota è 0 la lunghezza di una lista è 1 più la lunghezza del cdr della lista ! Possiamo anche definire length in stile iterativo (define (length items) (define (length-iter a count) (if (null? a) count (length-iter (cdr a) (+ 1 count)))) (length-iter items 0)) Carlo Strapparava - Informatica Esempio: append ! Un’altra tecnica comune è quello di costruire nuove liste con una successione di cons ! Es. La procedura append prende due liste come argomenti, e da queste forma una nuova lista (append lista-quadrati dispari) " (1 4 9 16 25 1 3 5 7) (append dispari lista-quadrati) " (1 3 5 7 1 4 9 16 25) Carlo Strapparava - Informatica 12 Esempio: append ! Per implementare append usiamo ancora un piano ricorsivo: ! Fai append di list1 list2 " " se list1 è la lista vuota, allora il risultato è list2 altrimenti, fai append del cdr di list1 con list2, e fai cons del car di list1 con questo risultato (define (append list1 list2) (if (null? list1) list2 (cons (car list1) (append (cdr list1) list2)))) Carlo Strapparava - Informatica Esercizi:last-pair e reverse (define (last-pair list) ;restituisce (if (null? (cdr list)) list (last-pair (cdr list)))) l’ultimo pair di una lista (define (reverse items) (if (null? items) nil (append (reverse (cdr items)) (list (car items))))) (define (reverse items) ;reverse in versione iterativa (define (rev-iter items acc) (if (null? items) acc (rev-iter (cdr items) (cons (car items) acc)))) (rev-iter items nil)) Carlo Strapparava - Informatica 13