Uvod
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.
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 take ho muzete s polu z jinymi najit na CMU)
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
(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
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
(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) 13no 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 ((xto 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:) (y )) (+ x y 5) )
> (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) 13asi neni co dodat...
> (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) 5Jsou 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.
> (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: 6pro 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
> (setq a 3) 3 > a 3 > (quote a) A > 'a ;'a is an abbreviation for (quote a) AJina 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 4val1...nemuzou se odkazovat na var1...:
> (let ((x 1) (y (+ x 1))) y ) Error: Attempt to take the value of the unbound symbol Xto dela potize pri:
> (setq x 7) 7 > (let ((x 1) (y (+ x 1))) y ) 8to umoznuje forma let*:
> (setq x 7) 7 > (let* ((x 1) (y (+ x 1))) y ) 2ta 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
> (setq regular 5) 5 > (defun check-regular () regular) CHECK-REGULAR > (check-regular) 5 > (let ((regular 6)) (check-regular)) 5Promene 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
> (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
> (concatenate 'string "abcd" "efg") "abcdefg" > (char "abc" 1) #\b ;LISP pise chary z #\ > (aref "abc" 1) #\b ;stringy jsou pole..vic zmatku:
> (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)
> (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) 3Takze 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
> (if t 5 6) 5 > (if nil 5 6) 6 > (if 4 5 6) 5if je napsano pomoci unless:
> (when t 3) 3 > (when nil 3) NIL > (unless t 3) NIL > (unless nil 3) 3when a unless narozdil od if berou vic forem v body casti:
> (when t (setq a 5) (+ a 6) ) 11je 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 ) 2pokud chybi akce cond vrati hodnotu podinky:
> (cond ((+ 3 4))) 7a mame tu i case:
> (setq x 'b) B > (case x (a 5) ((d e) 7) ((b f) 3) (otherwise 9) ) 3
> (setq a 4) 4 > (loop (setq a (+ a 1)) (when (> a 7) (return a)) ) 8 > (loop (setq a (- a 1)) (when (< a 3) (return)) ) NILVidite 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 NILdolist 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 32Neco 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) 3Muze 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 ) 7Temporary bloky jako smycky se vetsinou jmenujou nil. No a podobna forma je error:
> (error "This is an error") Error: This is an errorTa vsechno prerusi a vybombi.
> (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) 8Daji 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)
> (sort '(2 1 5 4 6) #'<) (1 2 4 5 6) > (sort '(2 1 5 4 6) #'>) (6 5 4 2 1)
> (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
> (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.
Tento soubor je soucasti rozsahle sbirky skolicek na http://www.ucw.cz/~hubicka/skolicky
Take si muzete prohlidnout jeji puvodni textovou podobu
Nebo mi mailnout na hubicka@ucw.cz
Copyright (C) Jan Hubicka 1995