Tahle skolicka je pro ty co se rozhodli zkusit v lispu neco udelat. Je to spis jenom seznam funkci. Vsechny zajimave konstrukce rozeberu ve specialnich skolickach. Common lisp je nejrozsirenejsi dialekt lispu. Vetsina ostatnich je snim docela kompatibilni. Je zcela univerzalni takze v nem jde udelat opravdu hodne. Ja osobne ho nepovazuju za nejlepsi podle me je moc komplikovanej. Jeho uplna specifikace je v: Guy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984. Tu knizku jsem nikdy necetl ani nevim kde se da splasit jediny co vim ze prvni vydani melo 500 stran a druhe uz 1000. To ukazuje jak tenhle standart je slozity. Proto jen naproste zaklady: (Budu se drzet tutorialnu dodavanym z clispem-soucast slakwaru) Symboly: ======== Common lisp vsechny symboly dava upper case(jako pascal). Promene: nastavovani promenych se dela pomoci setq. Lokalni promene se delaji pomoci let: > (setq a 5) ;ulozi cislo jako hodnotu symbolu 5 > a ;a je tam :) 5 > (let ((a 6)) a) ;docasny nastaveni acka na 6 6 > a ;a je zase spatky petka 5 > b ;nenastaveny symbol Error: Attempt to take the value of the unbound symbol B Self evaluating symboly: To jsou symboly co se vyhodnocuji samy do sebe-jejich obsach je zase tensymbol samozdrejme ze muzem takovy symbol udelat: (setq a 'a) Ale je tu nekolik specialnich: t a nil (true,false) jejich funkci jsem uz popsal Ale jsou tu jeste keywordy-to jsou taky self evaluating a zacinaji na : priklad: > :this-is-a-keyword :THIS-IS-A-KEYWORD > :me-too :ME-TOO Cisla: ====== integer: muze zacinat + - a nesmi obsahovat . dulezite je to, ze integer muze byt libovolne dlouhy-tedy pouziva uz popsanou knihovnu gmp. real: jako integer ale musi mit desetinou tecku taky jde vedecky zapis rational: zlomky-dva integery a / mezi complex: zapis: #c(r i) r i muze byt libovolny predchazejici typ a vsechny jsou zamozdrejme typu number a atomic priklady: 5 -34 +6 3.1415 1.722e-15 #c(1.722e-15 0.75) Ma funkce na beznou aritmetiku:+, -, *, /, floor,ceiling, mod, sin, cos, tan, sqrt, exp, expt atd.. Vsechno samozdrejme dela prislusne prevody nahoru-jako cecko: > (+ 3 3/4) ;prevod nahoru 15/4 > (exp 1) ;e 2.7182817 > (+ 5 6 7 (* 8 9 10)) ;fce +-/* berou vic argumentu Cons: ===== To uz bylo popsano tedy dve casti car a cdr(podle "contents of address register" a "contents of decrement register") zapis: (car.cdr) jsou tu tri funkce na praci:cons car a cdr. Funkce je asi jasna: > (cons 4 5) ;vytvori cons. Nastavi car na 4 a cdr na 5. (4 . 5) > (cons (cons 4 5) 6) ((4 . 5) . 6) > (car (cons 4 5)) 4 > (cdr (cons 4 5)) 5 Listy: ====== Jak uz jsem psal specialni forma consu, specialni format na tisknuti: (4 5 6) jde vytvorit funkci: > (list 4 5 6) (4 5 6) nebo: > '(4 5 6) (4 5 6) A samozdrejme pomoci funkce cons: > (cons 4 nil) (4) > (cons 4 (cons 5 6)) (4 5 . 6) > (cons 4 (cons 5 (cons 6 nil))) (4 5 6) List je pouzivan take jako zasobnik: > (setq a nil) NIL > (push 4 a) (4) > (push 5 a) (5 4) > (pop a) 5 > a (4) > (pop a) 4 > (pop a) NIL > a NIL (Takoveho zasobniku vyuziva treba funkce let nebo funcall) Funkce: ======= Ty jsou tu opravdu dobre udleane. Nekolik prikladu: > (+ 3 4 5 6) ;libovolny pocet parametru 18 > (+ (+ 3 4) (+ (+ 4 5) 6)) ;matematika je tu celkem srandovni... 22 > (defun foo (x y) (+ x y 5)) ;nova funkce FOO > (foo 5 0) ;a uz ji volame.. 10 > (defun fact (x) ;bezna rekurze-zkuste treba (fact 1995) to je teprve sranda! (if (> x 0); specialni forma if a jeji prvni parametr typu boolean (* x (fact (- x 1)));true vetev ifu 1;false vetev ) ) FACT > (fact 5);a pocitame! 120 > (defun a (x) (if (= x 0) t (b (- x)))) ;navzajem vnorene funkce slapou taky A > (defun b (x) (if (> x 0) (a (- x 1)) (a (+ x 1)))) B > (a 5) T > (defun bar (x) ;funkce z vice formama vraci hodnotu posledni (setq x (* x 3)) ;formy (setq x (/ x 2)) ;takze tyhle (+ x 4) ) BAR > (bar 6) 13 no takhle jsem si zablbnul naposled v basicu na sharpovi :) Kdyz nadefinujete foo z dvema parametrama-jako je v prikladu tak volani chce opravdu jen dva parametry-jinak to rve(to neni tak uplne bezne v lispech) Pri volani se samozdrejme letem udelaji dve promene-x a y a prvni parametr se vycisli do x a druhy do y takze volani foo se provede nejak takhle: (let ((x ) (y )) (+ x y 5) ) to presne udela funkce funcall-tady vidite ze i volani funkce jde v lispu nejak opsat. Common lisp dela navic lexikal scoping to znamena ze schova lokalni promene funkce pred volanim dalsi funkce-tedy funkce + uz nemuze zapisovat do promene x a y ktere pouziva funkce foo Jak jsem uz rikal lisp podporuje atributy parametru. Zakladni je &optional: > (defun bar (x &optional y) (if y x 0)); volitebny prarametr BAR > (defun baaz (&optional (x 3) (z 10)) (+ x z));tady se nastavuje default hodnota na neco jinyho nez standartni nil BAAZ > (bar 5) 0 > (bar 5 t) 5 > (baaz 5) 15 > (baaz 5 6) 11 > (baaz) 13 asi neni co dodat... Dalsi je &rest ktery se udava jen u posledniho parametru a spusobi ze dalsi parametry se nechaji v listu a predaji funkci-to pouziva treba funkce + > (defun foo (x &rest y) y) FOO > (foo 3) NIL > (foo 4 5 6) (5 6) No a posledni &key ktery vylepsuje nastavoavni promenych pri volani: > (defun foo (&key x y) (cons x y)) FOO > (foo :x 5 :y 3) (5 . 3) > (foo :y 3 :x 5) (5 . 3) > (foo :y 3) (NIL . 3) > (foo) (NIL) a samozdrejme default hodnota: > (defun foo (&key (x 5)) x) FOO > (foo :x 7) 7 > (foo) 5 Jsou tu jeste makra-funkce co nespracovavaji svoje parametry. To co je defun a funcall pro funkce je defmacro a exmand pro makra. Je nutne si hlidat tluceni lokalnich promenych a tak jejich psani je o neco slozitejsi. Tisteni: ======== Zaklad jsou funkce print a format. Nebudu vic rozebirat jen priklady: > (print 3) 3 3 > (format t "An atom: ~S~%and a list: ~S~%and an integer: ~D~%" nil (list 5) 6) An atom: NIL and a list: (5) and an integer: 6 pro tisteni ~ je ~~ Forms and the Top-Level Loop: ============================= Clisp podporu historii na tri zpet: > 3 3 > 4 4 > 5 5 > *** 3 > *** 4 > *** 5 > ** 4 > * 4 Specialni formy: ================ Uz jsem popsal jsou to tedy neco jako makra psana v cecku zaklad je quote co vraci svuj parametr a jde taky napsat jako ' > (setq a 3) 3 > a 3 > (quote a) A > 'a ;'a is an abbreviation for (quote a) A Jina specialni forma je function. priklady: > (setq + 3) 3 > + 3 > '+ + > (function +) # > #'+ ;#'+ is an abbreviation for (function +) # Binding: ======== K tomu jsou tu dve spec. formy let a let* volani: (let ((var1 val1) (var2 val2) ... ) body ) let udela lokalni promeni var1,var2... a da jim hodnoty val1,val2 atd... Poprovedeni body se promene opet zrusi priklady: > (let ((a 3)) (+ a 1)) 4 > (let ((a 2) (b 3) (c 0)) (setq c (+ a b)) c ) 5 > (setq c 4) 4 > (let ((c 5)) c) 5 > c 4 val1...nemuzou se odkazovat na var1...: > (let ((x 1) (y (+ x 1))) y ) Error: Attempt to take the value of the unbound symbol X to dela potize pri: > (setq x 7) 7 > (let ((x 1) (y (+ x 1))) y ) 8 to umoznuje forma let*: > (setq x 7) 7 > (let* ((x 1) (y (+ x 1))) y ) 2 ta vlastne dela: (let* ((x a) (y b)) ... ) je stejne jako: (let ((x a)) (let ((y b)) ... ) ) pokud je hodnota nil da se nahradit (var1 nil) varem primo Dynamic Scoping: ================ Let ma stejne pojeti lokalnich promenych jako v cecku tedy pri volani funkce se schovaji-to je lexical scoping. Dynamic scoping to dela stejne jako v basicu tedy neschova je Lexical scoping: > (setq regular 5) 5 > (defun check-regular () regular) CHECK-REGULAR > (check-regular) 5 > (let ((regular 6)) (check-regular)) 5 Promene co zustavaji se jmenuji specialni promene a vetsinou se pojmenuvavaji z * na zacatku a konci: *special* takove promene se delaji pomoci makra defvar: > (defvar *special* 5) *SPECIAL* > (defun check-special () *special*) CHECK-SPECIAL > (check-special) 5 > (let ((*special* 6)) (check-special)) 6 Pole: ===== To je dalsi clispovej typ. Vytvari se funkci make-array a funkci aref se pristupuje. Podporuji se i vicerozmerne pole: > (make-array '(3 3)) #2a((NIL NIL NIL) (NIL NIL NIL) (NIL NIL NIL)) > (aref * 1 1) NIL > (make-array 4) ;1D arrays don't need the extra parens #(NIL NIL NIL NIL) Cisluje se vzdy od 0 Stringy: ======== Je pole charu-dalsi typ. Zapis je uplne stejny jako v cecku. Vsechny funkce na pole pracuji i z stringy-specialni pripad pole. Je tu hodne stringovych funkci. Podporuje backshlasovou konevkci-\\ \" \n apod. priklady: > (concatenate 'string "abcd" "efg") "abcdefg" > (char "abc" 1) #\b ;LISP pise chary z #\ > (aref "abc" 1) #\b ;stringy jsou pole.. vic zmatku: concentrate funguje z libovolnou sentensi-sentense je list,string nebo pole preste neco z prvky. Maji spolecne funkce pro praci s nimi-jako aref: > (concatenate 'string '(#\a #\b) '(#\c)) "abc" > (concatenate 'list "abc" "de") (#\a #\b #\c #\d #\e) > (concatenate 'vector '#(3 3 3) '#(3 3 3)) #(3 3 3 3 3 3) Struktury: ========== Jsou vlastne listy popisu v zvlast v jine skolicce setf: ===== To je vlastne prace z ukazatelama-toho se casto vyuziva treba pri praci ze strukturama. setf je tedy vlastne neco jako *a=hodnota. Takze setf vyhodnoti svuj prni ukazatel, veme ho jako ukazatel a da tam svuj druhy vyhodnoceny parametr. Vpodstate kazdy objekt v lispu je ukazatel. Takze kdyz aref vraci nty prvek pole vraci vlastne ukazatel do toho pole kdyz nastavime promenou na jeho hodnotu objekt se rozdvoji. Ale kdyz zmenime hodnotu objektu na tom ukazatelu zmenime prvek pole: > (setq a (make-array 3)) #(NIL NIL NIL) > (aref a 1) NIL > (setf (aref a 1) 3) 3 > a #(NIL 3 NIL) > (aref a 1) 3 Takze to je jedina cesta na meneni hdonot prvku pole apod. vic prikladu: > (setf a (make-array 1)) ;setf na promenou je setq #(NIL) > (push 5 (aref a 1)) ;push muze fungovat jako setf-ono to vlastne setf je-zamyslete se (5) > (pop (aref a 1)) ;a samozdrejme muzem popovat 5 > (setf (aref a 1) 5) 5 > (incf (aref a 1)) ;incf je jako setf ale zvetsi o jedna 6 > (aref a 1) 6 Boolean: ======== nil je false vsechno jiny je true bezne se pro true pouziva t priklady: > (if t 5 6) 5 > (if nil 5 6) 6 > (if 4 5 6) 5 if je napsano pomoci unless: > (when t 3) 3 > (when nil 3) NIL > (unless t 3) NIL > (unless nil 3) 3 when a unless narozdil od if berou vic forem v body casti: > (when t (setq a 5) (+ a 6) ) 11 je tu ale treba i cond co funguje jako if..else if....fi konstrukce: > (setq a 3) 3 > (cond ((evenp a) a) ;if a jenom return a ((> a 7) (/ a 2)) ;else if a je vetsi nez 7 return a/2 ((< a 5) (- a 1)) ;else if a je mensi nez 5 return a-1 (t 17) ;else return 17 ) 2 pokud chybi akce cond vrati hodnotu podinky: > (cond ((+ 3 4))) 7 a mame tu i case: > (setq x 'b) B > (case x (a 5) ((d e) 7) ((b f) 3) (otherwise 9) ) 3 Smycky a spol: ============== Zaklad vseho je loop-ta pouzti body furt dokola dokud nevlitne na return- return je tu neco jako break v cecku: > (setq a 4) 4 > (loop (setq a (+ a 1)) (when (> a 7) (return a)) ) 8 > (loop (setq a (- a 1)) (when (< a 3) (return)) ) NIL Vidite a to je _ZCELA_ univerzalni smycka jednoducha umi vsechno Pak tu mame dolist nastavuje promenou na jednotlivy prvky listu a provadi body: > (dolist (x '(a b c)) (print x)) A B C NIL dolist vzdycky vrati nil. Takze to nil na konci neni z vypisu printem ale navratova hodnota. Jsou tu ale i slozitejsi treba do: > (do ((x 1 (+ x 1)) (y 1 (* y 2))) ((> x 5) y) (print y) (print 'working) ) 1 WORKING 2 WORKING 4 WORKING 8 WORKING 16 WORKING 32 Neco jako ceckarsky for: prvni cast jsou promeny a jaky hodnoty jim dat a jak je menit. Dalsi cast je podminka a navratova hodnota a nakonec je body. Opakuje se dokud je podminka false. je tu taky do* co funguje jako let* Non local exits: ================ To je forma return-ta ukonci provadeni body a nastavi navratovou hodnotu: > (defun foo (x) (return-from foo 3) x ) FOO > (foo 17) 3 Muze se vratit z libovolnyho bloku. Clisp ma na to konstrukci named block coz je skoro jako funkce. Toho vyuzivaji interne vsechny funkce co berou body: > (block foo (return-from foo 7) 3 ) 7 Temporary bloky jako smycky se vetsinou jmenujou nil. No a podobna forma je error: > (error "This is an error") Error: This is an error Ta vsechno prerusi a vybombi. Funcall, Apply, a Mapcar: ========================= To jsou funkce na volani funkci. Funcall uz znate. priklady: > (funcall #'+ 3 4) 7 > (apply #'+ 3 4 '(3 4)) 14 > (mapcar #'not '(t nil t nil t nil)) (NIL T NIL T NIL T) Apply je jako funcall ale posledni parametr muze byt list ktery se potom prida na konec parametru volane funkce tedy priklad zavola: (+ 3 4 3 4) Mapcar zavola funkci co bere jako fvuj prvni parametr postupne na vsechny prvky listu co bere jako svuj druhy parametr. Lambda: ======= clisp umi docasne funkce: > #'(lambda (x) (+ x 3)) (LAMBDA (X) (+ X 3)) > (funcall * 5) 8 Daji se tim delat smycky: > (do ((x '(1 2 3 4 5) (cdr x)) (y nil)) ((null x) (reverse y)) (push (+ (car x) 2) y) ) (3 4 5 6 7) > (mapcar #'(lambda (x) (+ x 2)) '(1 2 3 4 5)) (3 4 5 6 7) Trideni: ======== jen priklad: > (sort '(2 1 5 4 6) #'<) (1 2 4 5 6) > (sort '(2 1 5 4 6) #'>) (6 5 4 2 1) Shodnost: ========= V clispu je nekolik schodnosti:ciselna funkci = eq na symboly-dva symboly jsou eq kdyz jsou identicky takze dve kopije listu nejsou eq eql je jako eq pro symboly a - pro cisla a equal je jako eql ale pro consy opravdu porovnava tedy dve kopije listu jsou equal: > (eq 'a 'a) T > (eq 'a 'b) NIL > (= 3 4) T > (eq '(a b c) '(a b c)) NIL > (equal '(a b c) '(a b c)) T > (eql 'a 'a) T > (eql 3 3) T Prace z listy: ============== Takovych funkci je moc tedy jen priklady: > (append '(1 2 3) '(4 5 6)) ;concatenate lists (1 2 3 4 5 6) > (reverse '(1 2 3)) ;reverse the elements of a list (3 2 1) > (member 'a '(b d a c)) ;set membership -- returns the first tail (A C) ;whose car is the desired element > (find 'a '(b d a c)) ;another way to do set membership A > (find '(a b) '((a d) (a d e) (a b d e) ()) :test #'subsetp) (A B D E) ;find is more flexible though > (subsetp '(a b) '(a d e)) ;set containment NIL > (intersection '(a b c) '(b)) ;set intersection (B) > (union '(a) '(b)) ;set union (A B) > (set-difference '(a b) '(a)) ;set difference (B) No a ted jenom spustit emacs nastavit interpretr: ln -s /usr/local/bin/clisp ~/bin/lisp napsat M-x lisp-mode a programovat! M-x run-lisp spusti lisp. Kotelnik ......a ten nejkotlivejsi......