Nemrekurzív programozás ÜA LISP tartalmaz nemrekurzív eszközöket is, mivel azonban funkcionális nyelv, ezeket is függvényként használhatjuk. ÜSokszor a nemrekurzív függvények kevesebb tárat, ill. futási időt igényelnek. Iteratív függvények: LISP-ben az iteráció egy forma többszörös kiértékelését jelenti. Egy meghatározott feltétel teljesülésétől függ, hogy meddig kell a kiértékelést ismételnünk. Beépített függvények : DOTIMES, DOLIST, DO, DO*, LOOP
DOTIMES ÜSzintaxis: Ü(DOTIMES (indexváltozó n [eredm]) törzs) Működés: n-szer értékeli ki a törzs et, miközben indexváltozó értéke: 0-tól n-1-ig megy. Ezután visszatéríti eredm értékét, mely ha hiányzik (ugyanis opcionális), NIL-t eredményez. ÜPélda: Ü> (DOTIMES (i 4) (FORMAT t "~&I értéke ~S." i))FORMAT I értéke 0. I értéke 1. I értéke 2. I értéke 3. NIL
DOLIST ÜSzintaxis: Ü(DOLIST (indexváltozó lista [eredm]) törzs) Működés: habár ugyanaz a szintaxisa, mint a DOTIMES függvénynek, itt az indexváltozó értékeit egy lista elemeiből veszi. ÜPélda: > (DOLIST (x ’(piros sárga fehér) ’virágok) (FORMAT t "~&A rózsák ~S színűek." x)) A rózsák PIROS színűek. A rózsák SÁRGA színűek. A rózsák FEHÉR színűek. VIRÁGOK
Ciklusból való kilépés: RETURN A RETURN függvény alkalmazásakor a eredm értékét nem veszi figyelembe. Példa: A következő függvény, ELSŐ-PLAN egy lista első páratlan elemét adja meg. A DOLIST segítségével végighaladunk a lista elemein, majd a RETURN függvénnyel lépünk ki, ha találtunk egy ilyen elemet. Ü(DEFUN ELSŐ-PLAN (SZÁMLISTA) (DOLIST (E SZÁMLISTA) (FORMAT T "~&Tesztelés ~S..." E) (WHEN (ODDP E) (FORMAT T „páratlan szám...") RETURN E))))
DOLIST és RETURN A PLAN-VIZSGÁLAT függvény a DOLIST függvényt használja arra, hogy leellenőrizze egy lista minden elemét, páros számok-e. Ha igen, akkor a DOLIST eredménye a T szimbólum, különben rögtön leáll a ciklus, ha talál egy pá- ros elemet, és ekkor NIL -t ad vissza. Ü(DEFUN PLAN-VIZSGÁLAT (SZÁMLISTA) (DOLIST (E SZÁMLISTA T) (FORMAT T " ~& ~S vizsgálata..." E) (IF (NOT (ODDP E)) (RETURN NIL))))
Rekurzív, ill. iteratív keresés összehasonlítása (DEFUN REK-ELSO-PLAN (X) ;rekurzív definíció (COND ((NULL X) NIL) ((ODDP (FIRST X)) (FIRST X)) (T (REK-ELSO-PLAN (REST X))))) (DEFUN ITER-ELSO-PLAN (X) ;iteratív definíció (DOLIST (E X) (IF (ODDP E) (RETURN E))))
Rekurzív, ill. iteratív keresés összehasonlítása ÜSokszor kis előnyökkel jár az iteráció használata: A megállási feltétel implicit: DOLIST mindig megáll, amikor a lista végére ér. Iteratív esetben az E változó a lista egymás utáni elemeire utal. A rekurzív verzió esetében X a listának a farkát jelöli, majd annak a farkát és így tovább... ÜMáskor a rekurzió egyszerűbb és természetesebb, mint az iteráció: Például könnyebb, elegánsabb CAR/CDR rekurzióval keresni egy fában, mint iteratívan.
Faktoriális iteratívan Hozzárendelés, avagy a LET függvény használata iteratív függvény definiálásakor: Ü(DEFUN ITER-FAKT (N) (LET ((SZORZAT 1)) (DOTIMES (I N SZORZAT) (SETF SZORZAT (* SZORZAT (+ I 1))))))
Halmazok metszete iteratívan Ü(DEFUN ITER-INTERSECTION (X Y) (LET ((VÉGSŐ NIL)) (DOLIST (ELEM X VÉGSŐ) (WHEN (MEMBER ELEM Y) (PUSH ELEM VÉGSŐ))))) Megjegyzések: 1.Az ELEM változó az X halmaz elemein fut végig (megköti az elemeket bound) 2.PUSH makrófüggvény, lista elejére (verembe) betesz egy adott elemet. Társa: POP veremből kiveszi az utolsó elemet (ti. a lista fejét). Destruktívak!!!
DOLIST ? MAPCAR ? REKURZIÓ? ÜMAPCAR a legegyszerűbb mód egy függvényt egy adott listra elemeire alkalmazni. Ü(DEFUN NÉGYZET-LISTA (SZÁMLISTA) (MAPCAR #’(LAMBDA (N) (* N N)) SZÁMLISTA)) ÜA rekurzív megoldás bonyolultabb... Ü(DEFUN REK- NÉGYZET-LISTA (X) (COND ((NULL X) NIL) (T (CONS (* (FIRST X) (FIRST X)) (REK-NÉGYZET-LISTA (REST X)))))) ÜIteratív módszer: a DOLIST használatakor fel kell építenünk a megoldást explicit értékadással. Ü(DEFUN ITER- NÉGYZET-LISTA (SZÁMLISTA) (LET ((EREDM NIL)) (DOLIST (E SZÁMLISTA (REVERSE EREDM)) (PUSH (* E E) EREDM))))
DO A legerősebb iterációs forma Lispben. Bármely számú változót képes megkötni, akárcsak a LET ( egyszerre ) ; ÜSegítségével bonyolultabb ciklusokat építhetünk fel. ÜSzintaxisa: Ü(DO ((vált1 kezdért1 [lépés1]) (vált2 kezdért2 [lépés2]) ; DO -változók listája...) (feltétel tev-1... tev-n) ;megállási feltétel törzs)
DO A DO -változók lokális változók. Kezdeti értéket rendelhetünk hozzájuk, különben NIL lesz az értékük. Az utolsó S-kifejezés után nem fejeződik be a DO kiértékelése, hanem újra kiértékelődik a feltétel, és azt követően minden S- kifejezés, egészen addig, amíg a feltétel értéke igaz nem lesz. Ekkor értékelődik ki a megállási feltétel után álló tevékenység, és ennek értéke lesz a DO kifejezés visszatérő értéke.
A DO alkalmazása Ü(DEFUN FAKT (N) (DO ((I N (- I 1)) (EREDM 1 (* EREDM I))) ((ZEROP I) EREDM))) Ü(DEFUN IT-INTERSECTION (X Y) (DO ((X1 X (REST X1)) (EREDM NIL (IF (MEMBER (FIRST X1) Y) (CONS (FIRST X1) EREDM) EREDM))) ((NULL X1) EREDM))) Ü(DEFUN ELSO-PLAN-DO SZÁMLISTA) (DO ((X SZÁMLISTA (REST X))) ((NULL X) NIL) (IF (ODDP (FIRST X)) (RETURN (FIRST X)))))
DO* A DO* iteratív forma ugyanazzal a szintaxissal rendelkezik, mint a DO, csak ez szekvenciálisan (sorrendben) hozza létre és frissíti a változókat, mint a LET*, tehát nem egyszerre, mint a LET. Előnye az ELSŐ-PLAN típusú függvényekhez képest az, hogy segítségével értelmezni tudunk egy második indexváltozót, hogy együtt tartsuk egy lista egymásutáni elemeit, míg az első indexváltozó a lista farkára teszi ugyanezt: Ü(DEFUN ELSŐ-PLAN-DO* (SZÁMLISTA) (DO* ((X SZÁMLISTA (REST X)) (E (FIRST X) (FIRST X))) ((NULL X) NIL) (IF (ODDP E) (RETURN E))))
Feladatok Írjatok a ITER-MEMBER néven iteratív függvényt egy elem adott listában való megvizsgálására ( T vagy NIL legyen a visszatérített érték). ÜÉs hasonlóképpen: ÜITER-LENGTH ÜITER-NTH ÜITER-UNION ÜITER-REVERSE ÜITER-MAX
FORMAT A FORMAT függvény segítségével dolgokat tudunk kiírni a képernyőre vagy egy adott állományba. Első argumentuma a T szimbólum, ha a képernyőre íratunk ki. Második argumentuma egy karakterfűzér. Formatálási derektívákat is használhatunk, amelyek a ~ karakterrel kezdődnek. A ~% direktíva új sorba lépést eredményez. Ü> (FORMAT T „Első sor...~%ez már a második...") Első sor... ez már a második... NIL A ~& direktíva új sorba lépést eredményez, kivéve ha nem vagyunk már egy új sor elején. Egy másik formatálási direktíva a ~S, amely beszúrja egy Lisp objektum nyomtatási képét az üzenetbe, amit a FORMAT ki kell írjon. Ü(DEFUN BESZÉDES-NÉGYZET (N) (FORMAT T "~&~S négyzete ~S" N (* N N))) > (BESZÉDES-NÉGYZET 10) 10 négyzete 100 NIL Vissza
Input/Output FORMAT: formázott kiíratás FORMAT Ü>(FORMAT t “(Atom ~S lista ~S~%majd egész ~D~%” nil (list 5 6) 7) Atom NIL lista (5 6) majd egész 7 NIL READ: beolvasás a billenytűzetről program-vezérlés közben. Ü(DEFUN NÉGYZET () (FORMAT T „Kérem, adja meg a számot: ") (LET ((X (READ))) (FORMAT T "~S négyzete ~S.~%" X (* X X)))) > ( NÉGYZET ) Kérem, adja meg a számot: 7 7 négyzete 49. NIL
Fájlkezelés ÜREAD-LINE ÜPRINT ÜWRITE ÜWRITE-LINE ÜWRITE-STRING ÜWRITE-CHAR ÜOPEN ÜCLOSE
PÉLDA ÜA következő program állományt hoz létre, melyet a felhasználó feltölthet adatokkal, majd kilistázhatja a tartalmát.következő ÜForrás: felev-2001-osz/gyak4.txt