Imperativ programmering konstruktioner i Lisp Imperativ programmering I den imperativa programmeringen skriver vi program satsvist. Datastrukturer (kap.-.) aystruktur poststruktur Iterativa uttryck (avs.) do, dotimes, dolist, loop Satsvisa program med hopp (avs.) tagbody, go Blockstruktur (avs.) block, prog, return-from, return Jämförelse olika repetitiva strukturer läs in värden till a och b beräkna a+b och lägg resultatet i c skriv ut värdet av c I funktionella programmering skrev vi uttrycksvist: (skriv-ut (beräkna (läs-in a) (läs-in b Vi ser i den imperativa progrmmeringen variabler som utrymmen i vilket vi lägger värden. Med tilldelning kan vi lägga ett nytt värde i utrymmet. I den funktionella programmering ser vi bara värden. Hur dessa värden hanteras behöver vi egentligen inte veta. Vi inför de sammansatta datatyperna aystruktur och post. Vi tillåter att ändra i dataobjekt, t ex ändra pekare i en liststruktur eller ett värde i en aystruktur. Exempel på iterativt program - sortering Vi inför även repetitionsstrukturer. I den funktionella programmeringen använde vi rekursion. Arraystruktur (ay) Generaliserad tilldelning Tabell med pekare. Index från och uppåt. Elementen (dvs pekarna) ligger direkt efter varandra i minnet vilket medför direkt åtkomst av varje element (konstant tid). (setf plats nytt värde ) Plats är ett utrymme i vilket vi kan lagra ett värde. En plats anges med motsvarande selektorfunktion Selektorfunktionen för aystrukturen är: (aref ay index) och därför ges ett nytt värde till den platsen med (setf (aref ay index) värde) Selektorfunktionen för global variabel är: my-pi (dvs man skriver bara variabelet) (setf my-pi.5) Kallas även fält. En eller flera dimensioner. Endimensionella kallas vektorer. Flerdimensionella ibland matriser. index (a b c) (make-ay 5) - element initialiseras till nil (make-ay ( 5)) - xx5 matris (make-ay :inital-element ) - initialisera elementen till (make-ay :initial-contents ( )) - initialisera elementen från en lista 5 (setq v (vector )) => #( ) - extern notation (setf (aref v ) ) - generaliserade tilldelningen För global variabel är setf samma som setq v => #( ) (aref v ) => (setq m #(a b c d)) - som en konstant
5 6 Arraystruktur (ay) (setq (make-ay 5)) (setf (aref ) (a b c)) (setf (aref ) ) (setf (aref ) (make-ay :initial-contents (5 nil => #(nil (a b c) #(5 nil) nil) Ändra värdet 5 till. (setf (aref (aref ) ) ) => #(nil (a b c) #( nil) nil) (a b c) 5 Strukturer - poster En sammansatt struktur där elementen är pekare och anges med fält (i CommonLisp slotnames). kurser Med defstruct införs en ny datatyp. (defstruct dare kurser) Man får automatiskt tillgång till primitiva funktioner för att hantera objekt av denna datatyp. konstruktorfunktion (setq kalle (make-dare : Kalle : :kurser (prog diskmat => #S(dare : Kalle : :kurser (prog diskmat)) selektorfunktioner (dare- kalle) => Andra funktioner: (ay-total-size ) - storleken på aystrukturen => 5 (ayp ) => t (dare-kurser kalle) => (prog diskmat) mutatorfunktion (setf (dare- kalle) ) (dare-p kalle) => t recognizer -funktion 7 8 Dessutom för strukturer: Skönsvärden som anges vid typdeklarationen Utskriftsfunktion kan även anges (defstruct care ( )) (make-care : Nisse ) => #S(care : Nisse : ) - själv ange vad de genererade primitiverna skall heta (defstruct (klockslag (:print-function skriv-klockslag)) timme minut) (skapa-klockslag :timme 9 :minut ) => 9: (defstruct (care (:constructor skapa-care) (:predicate care?)) ) BOA-constructors, nyckelord behöver ej anges i konstruktorfunktionerna (defstruct (care (:constructor skapa-care ( ) (skapa-care Nisse )
9 Definiera strukturer i strukturer oblig nivå lithare profil care (defstruct lithare ) (defstruct (dare (:include lithare)) oblig profil) (defstruct (care (:include lithare)) nivå) (setq linus (make-lithare : Linus : )) (setq kalle-dare (make-dare : Kalle : :profil datorsystem :oblig t)) (setq lisa-care (make-care : Lisa : 5 :nivå kandidat)) (lithare- linus) => (lithare- kalle-dare) => (dare- kalle-dare) => (care- lisa-care) => 5 (lithare-profil..) fel (dare-profil kalle-dare) => datorsystem (care-nivå lisa-care) => magister dare Iterativa strukturer - repetition vanligen med styrvariabel iteration över lista: dolist (jämför med mapc) (defun my-length (l) (let ((counter )) (dolist (element l counter) (setq counter (+ counter)) iteration över tal: dotimes styrvariabel satser utförs n gånger i går från till n- (defun fak (n) (let ((result )) (dotimes (i n result) (setq result ( * (+ i) result) uttryck som ger listan man repeterar över uttryck som ger resultatet Generell iteration Satsvisa program med hopp loop - avslutas med return (defun my-length (list) (let ((counter )) (if (endp list) (return counter)) (setq counter (+ counter )) (setq list (rest list)) (defun fak (n) (let ((res )) (tagbody loop (if (= n ) (go end)) (setq res ( * n res)) (setq n (- n )) (go loop) end) res)) do-konstruktionen - besvärlig syntax (do ((styrvar init uppdatering) (styrvar init uppdatering)... ) (slutvillkor resultat-uttryck) sats... sats) Blockstruktur - ge på block (block test-block (print hej) (if (endp l) (return-from test-block värde) (print hopp)) Iterativa strukturer definierar implicita block. Därför kan dessa avslutas med return-from eller return (return värde) = (return-from nil värde)
Sekvensering av uttryck Implicit progn (motsvarande begin - end i Ada eller {} i Java) I positioner där vi tillåts skriva ett uttryck kan vi med progn (prog och prog) skriva flera uttryck. Bättre använda cond med implicit progn. (cond ((= n ) (format t n = ) (f n)) (t (format t n /= ) (g n (progn e e e... e n ) = värdet av e n (prog e e e... e n ) = värdet av e (if (= n ) (progn (format t n = ) (f n)) (progn (format t n /= ) (g n uttryck i varje gren Gäller även defun, let, labels mfl (defun utskrifter () (format t vad heter du? ) (format t jasså du heter ~s (read)) ) vad heter du? anders jasså du heter anders (prog n (setq n (+ n )) Ger värdet av gamla n 5 6 Varianter av if. Olika varianter av reverse - vända på en lista Om man bara önskar en gren av if-uttrycket kan man använda when eller unless. (when (= n ) (format t nu är n igen!!! )) (unless (listp l) (format t l är ej lista!!! )) Rekursiv funktion - rekursiv processlösning (if (endp l) () (append (rev (rest l)) (list (first l)) Rekursiv funktion - iterativ processlösning (labels ((rev-iter (l res) (if (endp l) res (rev-iter (rest l) (cons (first l) res)) (rev-iter l () Iterativ funktion med dolist (let ((res ( (dolist (e l res) (setq res (cons e res))
7 8 Iterativ funktion med do (do ((list l (rest list (res () (cons (first list) res ((endp list) res) )) Sortering av en vektor med selectionsort 6 8 5 9 5 6 7 Iterativ funktion med loop (let ((res ( (if (endp l) (return res)) (setq res (cons (first l) res)) (setq l (rest l)) För varje index i från start till slut- byt motsvarande elementet mot det minsta av elementen från detta i till slut. 8 6 5 9 5 6 7 Iterativ funktion med block+tagbody+hopp (let ((res ( (tagbody loop (if (endp l) (go end)) (setq res (cons (first l) res)) (setq l (rest l)) (go loop) end) res)) 8 6 5 9 5 6 7 6 5 8 9 5 6 7 9 (defun selection-sort (tab) (let ((maxindex (- (ay-total-size tab) (dotimes (index maxindex tab) ; från första till näst sista ; index byt element (switch-element tab index (index-min tab index maxindex)) ; returnerar tabellen som värde (defun index-min ( start end) (let ((min-value (aref start)) (index-for-min-value start) (index (+ start (cond Hitta index för minsta värdet från ett givet index ((> index end) (return index-for-min-value)) ; min-value resp min-index sätts ; till hittills minsta värde och ; dess index ((< (aref index) min-value) ; nytt mindre element (setf min-value (aref index)) (setf index-for-min-value index (setf index (+ index )) CL-USER(6): (setq test (vector 6 8 5 9)) #(6 8 5 9) CL-USER(7): (selection-sort test) : (INDEX-MIN #(6 8 5 9) 7) : returned : (INDEX-MIN #( 8 6 5 9) 7) : returned : (INDEX-MIN #( 8 6 5 9) 7) : returned 5 : (INDEX-MIN #( 6 5 8 9) 7) : returned 6 : (INDEX-MIN #( 5 8 6 9) 7) : returned : (INDEX-MIN #( 5 8 6 9) 5 7) : returned 6 : (INDEX-MIN #( 5 68 9) 6 7) : returned 6 #( 5 6 8 9) (defun switch-element ( i j) Byt värde för två index (let ((temp (aref j (setf (aref j) (aref i)) (setf (aref i) temp) ni)) ; inget intressant värde returneras