* General https://lispcookbook.github.io/cl-cookbook/ #+BEGIN_SRC lisp (defmacro until (test &rest body) `(do () (,test) ,@body)) (defmacro while (test &rest body) `(do () ((not ,test)) ,@body)) (defmacro with-gensyms ((&rest names) &body body) `(let ,(loop for n in names collect `(,n (gensym))) ,@body)) (char-name #\ ) => "Space" (char-code #\a) (code-char 65) (list #.(get-internal-real-time) (sleep 2) #.(get-internal-real-time)) ;; => #.(fn) will run at read/compile time, before eval time (declare (ignore var1 var2...)) vs (declare (ignorable var1 var2...)) #+END_SRC [[http://www.lispworks.com/documentation/HyperSpec/Body/v_rd_sup.htm#STread-suppressST][*read-suppress*]] Print new line
: terpri, fresh-line Never modify literal objects! '(a b c) "appleboy" ... * Files https://lispcookbook.github.io/cl-cookbook/files.html http://cl.com/14.files-and-file-io.htm ** Libraries *** alexandria (alexandria:read-file-into-string ...) ** Practical Common Lisp #+BEGIN_SRC lisp (defpackage :com.gigamonkeys.pathnames (:use :common-lisp) (:export :list-directory :file-exists-p :directory-pathname-p :file-pathname-p :pathname-as-directory :pathname-as-file :walk-directory :directory-p :file-p :parent-directory)) #+END_SRC ** Pathname #+BEGIN_SRC lisp (directory #P"**/*.lisp") ;; Recursive with ** (pathname-directory (pathname "/foo/bar/baz.txt")) ==> (:ABSOLUTE "foo" "bar") (pathname-name (pathname "/foo/bar/baz.txt")) ==> "baz" (pathname-type (pathname "/foo/bar/baz.txt")) ==> "txt" (pathname "/foo/bar/baz.txt") ==> #p"/foo/bar/baz.txt" (merge-pathnames #p"hello.txt" #p"~/Develop/Lisp/draft/") => #P"~/Develop/Lisp/draft/hello.txt" (namestring #p"/foo/bar/baz.txt") ==> "/foo/bar/baz.txt" (directory-namestring #p"/foo/bar/baz.txt") ==> "/foo/bar/" (file-namestring #p"/foo/bar/baz.txt") ==> "baz.txt" (ensure-directories-exist (probe-file "mine") #+END_SRC ** Read in Real Time #+BEGIN_SRC lisp (defmacro keep-reading ((var filename &optional (wait 0.3)) &body body) (with-gensyms (bye input output) `(let (,bye (,input *standard-input*) (,output *standard-output*)) (sb-thread:make-thread #'(lambda (standard-input) (until (member (read standard-input) '(bye end over))) ;; Or use ,input to replace another-input (setf ,bye t) (format ,output "Goodbye ~%") (princ "Bye!!")) :arguments (list *standard-input*)) (with-open-file (fifo ,filename :if-does-not-exist :create) (loop (let ((text (read-line fifo nil nil))) (when ,bye (format t "~&It's over, guy ~%") (return (format nil "Goodbye ~a" (now)))) (if text (let ((,var text)) ,@body) (sleep ,wait)))))))) #+END_SRC * [[http://www.lispworks.com/documentation/HyperSpec/Body/m_do_sym.htm][Packages]] [[http://reference-error.org/2015/08/30/common-lisp-finding-all-functions-in-a-package.html][Finding all functions in a package]] [[file:///Users/Can/Emacs/quicklisp/dists/quicklisp/software/manifest-20120208-git/manifest.lisp][manifest]] #+BEGIN_SRC lisp (lisp-all-packages) ; => Current active packages (package-used-by-list :celwk) (package-use-list :celwk) (find-symbol "=>" :celwk) ; (values >> :external) (find-symbol "*&*=>" :celwk) ; (values nil nil) (find-symbol "FORMAT" :celwk) ; (values format :inherited) Inherited from CL-USER (find-symbol "USERS" 'chat-service) ; (values users :internal) Not exported (find-all-symbols "FOO") (export 'something :celwk) (let ((i 0)) ;; List all exported symbol (do-external-symbols (sym *package*) (output "~&~3d: ~A" (incf i) sym))) #+END_SRC * Collection http://cl.com/11.collections.htm vector -> sequence list -> sequence coerce => Translate data type (coerce "Hello" 'list) => (#\H #\e #\l #\l #\o) copy-seq copy-list copy-tree :adjustable t ** Get #+begin_src lisp (elt '(1 2 3) 1) => (elt #(1 2 3) 1) => 2 (setf (elt *x* 0) 10) svref simple-vector index => element (setf (svref simple-vector index) new-element) ; Accesses the element of simple-vector specified by index. (aref "this is a test" 3) => (char "this is a test" 3) => (elt "this is a test" 3) => #\s (aref '(1 2 3) 2) => error #+end_src ** Multiple Dimension Array (defparameter x (make-array '(2 2 4) :initial-element 0)) => #3A(((0 0 0 0) (0 0 0 0)) ((0 0 0 0) (0 0 0 0))) (setf (aref x 1 1 0) 333) => #3A(((0 0 0 0) (0 0 0 0)) ((0 0 0 0) (333 0 0 0))) (aref x 1 1 0) => 333 (array-dimension ...) ** Sequence iterating functions #+begin_src lisp :test :key :start :end :from-end :count (count 1 #(1 2 1 2 3 1 2 3 4)) ==> 3 (remove 1 #(1 2 1 2 3 1 2 3 4)) ==> #(2 2 3 2 3 4) (remove 1 '(1 2 1 2 3 1 2 3 4)) ==> (2 2 3 2 3 4) (remove #\a "foobarbaz") ==> "foobrbz" (substitute 10 1 #(1 2 1 2 3 1 2 3 4)) ==> #(10 2 10 2 3 10 2 3 4) (substitute 10 1 '(1 2 1 2 3 1 2 3 4)) ==> (10 2 10 2 3 10 2 3 4) (substitute #\x #\b "foobarbaz") ==> "fooxarxaz" (substitute 'x 1 '(1 2 (3 2 1) ((1 1) (2 2)))) => (x 2 (3 2 1) ((1 1) (2 2))) (subst 'x 1 '(1 2 (3 2 1) ((1 1) (2 2)))) => (x 2 (3 2 x) ((x x) (2 2))) ;; Deep/Recursive ;; Shallow substitute substitute-if substitute-if-not nsubstitute nsubstitude-if nsubstitute-if-not ;; Deep: subst subst-if subst-if-not nsubst nsubst-if nsubst-if-not (find 1 #(1 2 1 2 3 1 2 3 4)) ==> 1 (find 10 #(1 2 1 2 3 1 2 3 4)) ==> nil (position 1 #(1 2 1 2 3 1 2 3 4)) ==> 0 (find "bc" "abcdef") => Not workd, only find char, to find substring, use search or cl-ppcre (member x list) :substring (subseq "foobarbaz" 3) ==> "barbaz" (subseq "foobarbaz" 3 6) ==> "bar" :sort :merge sort stable-sort (sort (vector "foo" "bar" "baz") #'string<) ==> #("bar" "baz" "foo") (setf my-sequence (sort my-sequence #'string<)) (merge 'vector #(1 3 5) #(2 4 6) #'<) ==> #(1 2 3 4 5 6) (merge 'list #(1 3 5) #(2 4 6) #'<) ==> (1 2 3 4 5 6) :subsequence :subseq (defparameter *x* (copy-seq "foobarbaz")) (setf (subseq *x* 3 6) "xxx") ; subsequence and new value are same length ==> "fooxxxbaz" (setf (subseq *x* 3 6) "abcd") ; new value too long, extra character ignored. ==> "fooabcbaz" (setf (subseq *x* 3 6) "xx") ; new value too short, only two characters changed ==> "fooxxcbaz" (position #\b "foobarbaz") ==> 3 (search "bar" "foobarbaz") ==> 3 (mismatch "foobarbaz" "foom") ==> 3 (mismatch "foobar" "bar" :from-end t) ==> 3 :predicate (every #'evenp #(1 2 3 4 5)) ==> nil (some #'evenp #(1 2 3 4 5)) ==> t (notany #'evenp #(1 2 3 4 5)) ==> nil (notevery #'evenp #(1 2 3 4 5)) ==> t (every #'> #(1 2 3 4) #(5 4 3 2)) ==> nil (some #'> #(1 2 3 4) #(5 4 3 2)) ==> t (notany #'> #(1 2 3 4) #(5 4 3 2)) ==> nil (notevery #'> #(1 2 3 4) #(5 4 3 2)) ==> t :mapping (map 'vector #'* #(1 2 3 4 5) #(10 9 8 7 6)) ==> #(10 18 24 28 30) (map-into a #'+ a b c) => (setf a (mapcar #'+ a b c)) (reduce #'+ #(1 2 3 4 5 6 7 8 9 10)) ==> 55 :initial-value #+end_src ** hash table :map:hash:table: gethash remhash clrhash with-hash-table-iterator #+begin_src lisp (defmacro sethash (key value hash) `(setf (gethash ,key ,hash) ,value)) ;; equals to: (defun set-hash (key value hash) (setf (gethash key hash) value)) (defun printhash (hash) (maphash #'(lambda (k v) (format t "~a: ~a ~%" k v)) hash)) (defun print-hash (hash) (maphash #'(lambda (k v) (print `(,k ,v))) hash)) (defparameter *h* (make-hash-table)) (gethash 'foo *h*) ;==> nil multiple-value-bind (setf (gethash 'foo *h*) 'quux) ;==> setf (gethash 'foo *h*) ;==> quux (maphash #'(lambda (k v) (format nil "~a => ~a~%" k v)) *h*) ;==> maphash always return nil (with-hash-table-iterator ...) (maphash #'(lambda (k v) (when (< v 10) (remhash k *h*))) *h*) ;==> remhash (loop for k being the hash-keys in *h* using (hash-value v) collect (format nil "~a => ~a~%" k v)) ;==> collect the values ;; do (format t "~a => ~a~%" k v)) #+end_src ** String Create a string stream => (make-string-output-stream) Create a stream FROM string (make-string-input-stream "1 one ") #+BEGIN_SRC lisp (let ((string-stream (make-string-input-stream "1 one "))) (list (read string-stream nil nil) (read string-stream nil nil) (read string-stream nil nil))) (let ((s (make-string-output-stream))) (write-string "testing... " s) (prin1 1234 s) (get-output-stream-string s)) (with-output-to-string (*standard-output*) (write-string "books" nil :end 3) (write-string "worms" *standard-output* :start 1)) write-string /write-line write-char (with-output-to-string (*standard-output*) (output "What")) == (input "What") (eq 'xx (read-from-string "xx")) => t (write-to-string 'xx) => "xx" #+END_SRC ** [[http://docs.com/CL-PPCRE-RegularExpression.htm][Regular Replace]] #+BEGIN_SRC lisp (regex-replace-all "-([a-z])" "the-count-address" (^(m char) (string-upcase char)) :simple-calls t) => "theCountAddress" (regex-replace-all "[A-Z]" "theCountAddress" $(input "-~A" (string-downcase *)) :simple-calls t) => "the-count-address" #+END_SRC * Sets ** functions #+begin_src lisp pushnew adjoin intersection nintersection ;; return the elements of list1 which are not in list2. set-difference nset-difference ;; return new list of elements appearing exactly once in list1 and list2. set-exclusive-or nset-exclusive-or union nunion member member-if member-if-not remove-duplicates #+end_src * List http://cl.com/12.they-called-it-lisp-for-a-reason-list-processing.htm the n stands for non-consing, meaning it doesn't need to allocate any new cons cells reverse => nreverse append => nconc subsititute => nsubstitute remove** => delete, delete-if, delete-if-not, and delete-duplicates (list* 1 '(2 3 4)) => (append '(1) '(2 3 4)) * Loops Iteration https://lispcookbook.github.io/cl-cookbook/iteration.html http://cl.com/22.loop-for-black-belts.htm collecting, counting, summing, minimizing, or maximizing across, and, below, collecting, counting, finally, for, from, summing, then, and to * Stream *readtables* http://www.lispworks.com/documentation/HyperSpec/Body/02_aa.htm #+BEGIN_SRC lisp (make-broadcast-stream ...) (make-string-input-stream "1.23") => a stream (with-output-to-string (out) (format out "hello, world ") (format out "~s" (list 1 2 3))) => "hello, world (1 2 3)" (get-output-stream-string stream) (write-to-string obj...) (with-input-from-string (s "1.23") (read s)) => 1.23 (eq 'luck (read-from-string (write-to-string 'luck))) (defmacro keep-reading ((var filename &key (byes '(bye end over)) (wait 0.3)) &body body) "Keep read a file, will invoke body when content added" (with-gensyms (bye input output) `(let (,bye (,input *standard-input*) (,output *standard-output*)) (sb-thread:make-thread #'(lambda (standard-input) (until (member (read standard-input) ,byes)) ;; Or use ,input to replace another-input (setf ,bye t) (format ,output "Goodbye ~%") (princ "Bye!!")) :arguments (list *standard-input*)) (with-open-file (fifo ,filename :if-does-not-exist :create) (loop (let ((text (read-line fifo nil nil))) (when ,bye (format t "~&It's over, guy ~%") (return (format nil "Goodbye ~a" (now)))) (if text (let ((,var text)) ,@body) (sleep ,wait)))))))) #+END_SRC * Threads #+BEGIN_SRC lisp (ql:quickload lparallel) (setf lparallel:*kernel* (lparallel:make-kernel 4)) ;; map-reduce !!?? (defun test () (map 'vector 'middle-square *seeds* *repetitions*)) ;; VS (defun ptest () (lparallel:pmap 'vector 'middle-square *seeds* *repetitions*)) #+END_SRC * Macros ** Variables rotatef (rotatef a b) a <=> b shiftf (shiftf a b 10) a => b, b => 10, return origin a 任何展开为 setf 表达式的宏调用都可以作为 setf 表达式的第一个参数 http://clhs.lisp.se/Body/f_symb_5.htm #+BEGIN_SRC lisp (defun last1 (lst) (car (last lst))) (defun (setf last1) (value lst) "Update the last one's value (setf (last1 alst) value)" (setf (car (last lst)) value)) ; Any macro call whose expansion could be the first argument to s e t f can itself be the first argument to setf (defmacro cah (lst) `(car ,lst)) (setf (cah x) 44) => (setf (car x) 44) (eq (symbol-value (read-from-string "xX")) xx) ; t (eq (symbol-value 'var) var) => var maybe a lambda or a data (setf (symbol-value 'name) 'erik) => (setf name 'erik) ; setfable ;; SYMBOL-VALUE cannot see lexical variables. (setf (symbol-value 'a) 1) (let ((a 2)) (symbol-value 'a)) => 1 (let ((a 2)) (setq a 3) (symbol-value 'a)) => 1 (SYMBOL-FUNCTION 'fn) => (fn ...) (boundp 'var) (read-from-string "Can") => 'can (read-from-string ":Can") => :can (fboundp 'func) (symbol-function 'func) ;;SETFable (symbol-name 'Can) => "CAN" (symbol-name :can) => "CAN" (symbol-name :|Can|) => "Can" (makunbound 'var-or-func) ;; Remove variable definition (fmakunbound 'func) ;; Remove/Unbound function or macro definition (remove-method #'dispose->user (find-method #'dispose->user nil '((eql :about-us) t t))) (values 1 2 3) == (values-list '(1 2 3)) ;; multiple value-* : (multiple-value-list (get-decoded-time)) => (59 40 7 ...) (multiple-value-bind (second minute hour date month year day-of-week dst-p tz) (get-decoded-time) ...codes) (multiple-value-call #'+ (values 1 4) (values 5 6)) => (+ 1 4 5 6) (setf (values *x* *y*) (floor (/ 57 34))) ,*x* => 1 ,*y* => 23/34 ;; DESCTRUCTURING-BIND (destructuring-bind (x y z) (list 1 2 3) (list :x x :y y :z z)) ==> (:X 1 :Y 2 :Z 3) (destructuring-bind (x y z) (list 1 (list 2 20) 3) (list :x x :y y :z z)) ==> (:X 1 :Y (2 20) :Z 3) (destructuring-bind (x (y1 y2) z) (list 1 (list 2 20) 3) (list :x x :y1 y1 :y2 y2 :z z)) ==> (:X 1 :Y1 2 :Y2 20 :Z 3) (destructuring-bind (x (y1 &optional y2) z) (list 1 (list 2 20) 3) (list :x x :y1 y1 :y2 y2 :z z)) ==> (:X 1 :Y1 2 :Y2 20 :Z 3) (destructuring-bind (x (y1 &optional y2) z) (list 1 (list 2) 3) (list :x x :y1 y1 :y2 y2 :z z)) ==> (:X 1 :Y1 2 :Y2 NIL :Z 3) (destructuring-bind (&key x y z) (list :x 1 :y 2 :z 3) (list :x x :y y :z z)) ==> (:X 1 :Y 2 :Z 3) (destructuring-bind (&key x y z) (list :z 1 :y 2 :x 3) (list :x x :y y :z z)) ==> (:X 3 :Y 2 :Z 1) (destructuring-bind (&whole whole &key x y z) (list :z 1 :y 2 :x 3) (list :x x :y y :z z :whole whole)) #+END_SRC ** [[http://clhs.lisp.se/Body/02_d.htm][Standard Macro Characters]] *** [[http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_del.htm][read-delimited-list]] (read-delimited-list #\] stream) *** [[http://clhs.lisp.se/Body/02_dh.htm][Sharpsign #]] dispatch char purpose dispatch char purpose Backspace signals error { undefined* Tab signals error } undefined* Newline signals error + read-time conditional Linefeed signals error - read-time conditional Page signals error . read-time evaluation Return signals error / undefined Space signals error A, a array ! undefined* B, b binary rational " undefined C, c complex number # reference to = label D, d undefined $ undefined E, e undefined % undefined F, f undefined & undefined G, g undefined ' function abbreviation H, h undefined ( simple vector I, i undefined ) signals error J, j undefined *  bit vector K, k undefined , undefined L, l undefined : uninterned symbol M, m undefined ; undefined N, n undefined < signals error O, o octal rational = labels following object P, p pathname > undefined Q, q undefined ? undefined* R, r radix-n rational @ undefined S, s structure [ undefined* T, t undefined \ character object U, u undefined ] undefined* V, v undefined ^ undefined W, w undefined _ undefined X, x hexadecimal rational ` undefined Y, y undefined | balanced comment Z, z undefined ~ undefined Rubout undefined ** Symbol Macro #+begin_src common-lisp (find-symbol "=>" :celwk) ; (values >> :external) (find-symbol "*&*=>" :celwk) ; (values nil nil) (find-symbol "FORMAT" :celwk) ; (values format :inherited) Inherited from CL-USER (find-symbol "USERS" 'chat-service) ; (values users :internal) Not exported (define-symbol-macro ln (length name)) => globally (symbol-macrolet sm (random 100)) => locally (set-macro-character #\$ #'dollar-sign t) => ($(+ 1 $1) 5) (defun lastguy (x) (car (last x))) ;; http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_3.htm (define-setf-expander (lastguy) (x &environment e) ...) => (setf (lastguy someone) ...) DEFINE your OWN setf for some expression (defsetf access-fn update-fn) ;; http://clhs.lisp.se/Body/m_defset.htm (defsetf symbol-value set) ;;=> (setf (symbol-value foo) fu) -> (set foo fu) #+end_src ** Symbol => Keywords #+begin_src common-lisp (intern (string 'xxx) :keyword) => :xxx (string 'foo) => "FOO" #+end_src * Debug [[https://slime-user-manual-cn.readthedocs.io/en/latest/chapter-3.html#id21][检查命令]] [[https://slime-user-manual-cn.readthedocs.io/en/latest/chapter-4.html][SLDB:Slime调试器]] [[https://malisper.me/debugging-lisp-part-1-recompilation/][Debugging Lisp Part 1: Recompilation]] http://www.sbcl.org/manual/#Function-Tracing slime-who-calls #+BEGIN_SRC lisp (dribble ...) ;; (desc dribble) ! (declaim (optimize (debug 3))) ; => For Debugging (step code) (trace func-name :wherein func ; => Only trace inside func or one of a function list: (fn1 fn2 fn3) :print-after (get-universal-time) ; => Manually print something :report nil ; => Print the invoker records :break (= 0 (sb-debug:arg 0))) (untrace func-name) (inspect *something*) (defmethod something ((i integer) (ls list) xx) (list (length ls) i xx)) (find-method #'something nil '(integer list t)) ;; (find-method #'something nil '(t)) => Error, not match the args type and count (remove-method #something (find-method #'something '() '(integer list t))) ;; Only remove the mactching one method (remove-method #'dispose->user (find-method #'dispose->user '() '((eql :about-us) t t))) (remove-method (find-method #'frob '(:before) '(admin t))) ;; admin is a CLASS (ppcre:regex-apropos "lo.*lo.*la" :cl) ;; => load-logical-pathname-translations [compiled closure] ;; SLIME: (break) "C-h m" in *sldb* mode to list the key shortcuts :Commands to examine the selected frame: t - toggle details (local bindings, CATCH tags) v - view source for the frame e - eval in frame d - eval in frame, pretty-print result D - disassemble i - inspect ;; Important! Commands to invoke restarts: q - quit a - abort c - continue 0-9 - restart shortcuts I - invoke restart by name Commands to navigate frames: n - down p - up M-n - down, with details M-p - up, with details TAB - cycle between restarts & backtrace < - beginning of backtrace > - end of backtrace Miscellaneous commands: r - restart frame R - return from frame s - step B - switch to native debugger A - switch to system debugger (gdb) : - eval C - inspect signalled condition ;; https://malisper.me/debugging-lisp-part-2-inspecting/ ;; Inspecting ;; When cursor in an Object, e.g # :check-values: M-o (slime-inspect-presentation-at-point POINT) ;; OR right click the object and select Inspect (slime-who-calls) (slime-who-references) => For Variables (slime-who-macroexpands) :*slime-inspector* After selecting some points ([ ] => [X], move point there and Enter), press [set value] to update value...(Useful!) :trace-function-calls: C-c M-t (slime-trace-dialog-toggle-trace &optional USING-CONTEXT-P) Then run the code/function you are tracing, then: C-c T (slime-trace-dialog &optional CLEAR-AND-FETCH) ; G to refresh To check the function call records! ;; untrace it when finished TAB slime-inspector-next-inspectable-object RET slime-inspector-operate-on-point C-x Prefix Command ESC Prefix Command SPC slime-inspector-next . slime-inspector-show-source > slime-inspector-fetch-all d slime-inspector-describe e slime-inspector-eval g slime-inspector-reinspect h slime-inspector-history l slime-inspector-pop n slime-inspector-next p slime-inspector-pprint v slime-inspector-toggle-verbose slime-inspector-previous-inspectable-object slime-inspector-previous-inspectable-object slime-inspector-operate-on-point ;; /Users/Can/Emacs/quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fancy-inspector.lisp M-RET slime-inspector-copy-down-to-repl sldb-copy-down-to-repl #+END_SRC * Math "Representation is the essence of programming." https://lispcookbook.github.io/cl-cookbook/numbers.html http://cl.com/10.numbers-characters-and-strings.htm [[http://www.lispworks.com/documentation/HyperSpec/Body/f_floorc.htm][FLOOR, FFLOOR, CEILING, FCEILING, TRUNCATE, FTRUNCATE, ROUND, FROUND]] ** Complex #+BEGIN_SRC lisp (complex (+ 1 2) 5) => #C(3 5) (realpart #C(7 9)) => 7 (imagpart #C(4.2 9.5)) => 9.5 #+END_SRC * Lisp Shell ** Environmental Variable #+BEGIN_SRC lisp ;; SHELL environment: ;; WHO="Savior Can" sbcl ;; * (posix-getenv "WHO") => "Savior Can" ;; 7.7 Support For Unix (sb-ext:posix-environ) (sb-ext:posix-getenv name) (sb-unix::posix-getenv "USER") CL-USER: *posix-argv* ;; Shell arg list => ("/usr/local/bin/sbcl" ...) #+END_SRC * Tools ** QuickLisp 在 SLIME 安装不了的代码库直接在shell 运行 sbcl 来安装!!例如: *** Library #+BEGIN_SRC lisp (ql:quickload :cl-html5-parser) ; => For Search Engine (ql:quickload :closer-mop) ; => MetaObject #+END_SRC ** SLIME Keys C-h a "slime.*\(who\|calle\)" #+BEGIN_SRC elisp ;; Compile Load ("C-c Return" 'slime-expand-1) ;; => Expand the macro, curosr at the beging of the parenthesis, may run deeply C-- Undo to go back level 'g' to refresh ("C-c C-l" 'slime-load-file) ("C-c C-c" 'slime-compile-defun) ("C-c C-k" 'slime-compile-file) ;; Auto save(editted by me), compiled to *fasl and load the file ;; Save Load and Go ("M-s M-s" 'save-and-load-lisp) ;; Save (the buffer and eval the entire buffer) and go to REPL ("M-s M-f" 'complete-defun-or-defmacro) ;; Save and go to slime output buffer ;; Go ("C-c C-z" 'slime-switch-to-output-buffer) ("C-c C-y" 'slime-call-defun) ;; Go to REPL, and call the function in the cursor ;; Edit ("C-c C-q" 'slime-close-all-parens-in-sexp) ;; C-c C-] ("C-j" 'slime-close-all-parens-in-sexp) ("C-C M-q" 'slime-reindent-defun) ;; # userful 重新缩进 ("M-C-a" 'slime-beginning-of-defun) ("M-C-e" 'slime-end-of-defun) M-x slime-scratch ;; Run ("C-c C-c" 'slime-compile-defun) ("C-x C-e" 'slime-eval-last-expression) ("C-c C-e" 'slime-interactive-eval) ;; Read and evaluate STRING and print value in minibuffer. ("C-c C-e, C-c :" 'slime-interactive-eval) ;; REPL ("C-j" 'slime-repl-newline-and-indent) ("C-M-k" 'slime-repl-clear-buffer) ;; C-c M-o ("C-c C-o" 'slime-repl-clear-output) ;; Clear the output from last eval ;C-M-b/f/p/n ;Go to the corresponding sexp parenthesis (backward = prevous forward = next) ("M-n" 'slime-repl-next-input) ("M-p" 'slime-repl-previous-input) ("M-s" 'slime-repl-revious-next-input) ("M-r" 'slime-repl-revious-matching-input) ;; Most useful!! ("C-c C-n" 'slime-repl-next-prompt) ("C-c C-p" 'slime-repl-previous-prompt) ;; Sometimes ;; SBCL (apropos "keyword") (apropos-list "xxx") (ppcre:regex-apropos "lo.*lo.*la" :cl) ;; Debug ;; c Continue ;; a Abort ;; q Quit debugger ;; v Locate source ;; Useful!! ;; D Disassemble source ;; e Evaluate prompted form in lexical context of current frame ;; Like po in Xcode ;; i Inspect prompted form (evaluated in lexical context of current ;; Like po in Xcode C-c C-c or C-c C-b 'slime-interrupt ("C-M-d" 'desc) ;; Find ("M-." 'slime-edit-definition) ;; !!! Useful !!! Go to the definition of function at point. ;; Mine ("C-M-t" 'time-code) ("C-c C-d f" 'slime-describe-function) ;; Describe the function at point. M-TAB [Useful] 'slime-complete-symbol (documentation #'name 'function) (describe #'name) (defun desc (symbol) (documentation symbol 'function)) (desc 'boundp) ;; Update: (setf (documentation var type) doc) change-directory (aka !d, cd) ;; For emacs C-x + Make all windows the same height (balance-windows). To cut the text, press C-w. To copy the text, press M-w. To paste the text, press C-y. paste back: M-y C-x { is bound to shrink-window-horizontally C-x } is bound to enlarge-window-horizontally C-x ^ is bound to enlarge-window C-x C-w Save to C-x h mark-whole-buffer (Select all region ) M-x load-file M-x show-paren-mode C-z or M-: ;; Execute emacs command C-h l view-lossage ;; Check the last operation, use it to create interactive functions!! Go back to previous line position (or "C-u C-space" "C-u C-@") If you want to navigate back between buffers, you can use: (or "C-x C-space" "C-x C-@") #+END_SRC ** SBCL (lisp-implementation-version) (lisp-implementation-type) ** Nginx nginx -g "daemon off;" Run in foreground, won't return until stopping * Syntax http://www.lispworks.com/documentation/HyperSpec/Body/02_aa.htm set-syntax-from-char set-macro-character with-standard-io-syntax ** &KEY #+begin_src lisp (defun test-xy (&key ((:x xxx) 0) ((y y) 0)) ;; rename the arg (list xxx y)) ;; => (test-xy :x 55 'y 66) => '(55 66) (do ((x (prepare-and-compute-the-next-value) (prepare-and-compute-the-next-value)) ;; more ...)) (do ((x #42=(prepare-and-compute-the-next-value) #42#) ;; more ...)) (let ((*readtable* (my-new-readtable))) ;; experiment with new readtable, it will recover after this LET ) #+end_src * [[https://lispcookbook.github.io/cl-cookbook/clos.html#mop][CLOS]] ** Examples #+BEGIN_SRC lisp (defclass person () ((name :initarg :name :accessor name) (species :initform 'homo-sapiens :accessor species :allocation :class))) ; => static/global field #+END_SRC ** String Output/Description The returned string of write-to-string or (format nil "~s" obj) https://stackoverflow.com/questions/7382122/lisp-how-to-override-default-string-representation-for-clos-class http://www.lispworks.com/documentation/HyperSpec/Body/m_pr_unr.htm #+begin_src lisp (defclass foo () ((name :accessor foo-name))) (defmethod print-object ((obj foo) stream) (print-unreadable-object (obj stream :type t) (format stream "~s" (foo-name obj)))) #+end_src ** Important Concept 1. Every class is also a type, but not every type is a class. 2. xx #+BEGIN_SRC lisp (type-of *room-user*) ; => chat-server => Just a symbol (class-of *room-user*) ; => # (slime-inspect-presentation-at-point) M-o (inspect *room-user*) (find-class 'chat-user) (class-name (find-class 'chat-user)) (type? *room-user* (class-of *room-user*)) => t (defclass foo () ()) (defparameter *f* (make-instance 'foo)) (typep *f* 'foo) => t (defun test (x) (typecase x (number (1+ x)) (foo :foo) (otherwise nil))) (mapcar 'test (list 42 *f* "foo")) => (43 :foo nil) (subtypep (type-of *room-user*) 'websocket-resource) => t (subtypep 'chat-user 'websocket-client) => t (closer-mop:class-precedence-list (find-class 'chat-user)) => List the class Inheritances (ql:quickload :closer-mop) (defmethod (setf name) (new-val (obj person)) => Override SETF (if (equalp new-val "james bond") (format t "Dude that's not possible.~&") (setf (slot-value obj 'name) new-val))) (setf (name p1) "james bond") => "Dude that's not possible" No rename (closer-mop:generic-function-methods #'text-message-received) => List the implemented hierarchy (when (next-method-p) (call-next-method)) (unintern 'person) => Delete a class (defmethod initialize-instance :after ((obj person) &key) (with-slots (name) obj (assert (>= (length name) 3)))) (make-instance 'person :name "me" ) ;; The assertion (>= #1=(LENGTH NAME) 3) failed with #1# = 2. ;; [Condition of type SIMPLE-ERROR] (defmethod initialize-instance :after ((obj person) &key) (with-slots (name) obj (assert (>= (length name) 3) (name) ;; creates a RESTART that offers to change "name" "The value of name is ~a. It should be longer than 3 characters." name))) (defgeneric update-instance-for-redefined-class (instance added-slots discarded-slots property-list &rest initargs)) => E.g (x y) => (theta rho): (# (theta rho) (y x) (y 200 x 100)) #+END_SRC (defmethod update-instance-for-redefined-class :before ((pos point) ...)) => [[https://malisper.me/debugging-lisp-part-3-redefining-classes/][Update the existing objects of a Class after updating the Class]] ** Meta Class https://lispcookbook.github.io/cl-cookbook/clos.html#mop closer-mop #+BEGIN_SRC lisp (defclass counted-class (standard-class) ((counter :initform 0))) ; # (defclass person () ((name :initarg :name :accessor name)) (:metaclass counted-class)) ;; <- metaclass (defmethod closer-mop:validate-superclass ((class counted-class) (superclass standard-class)) t) (defmethod make-instance :after ((class counted-class) &key) (incf (slot-value class 'counter))) ;; # (defvar p3 (make-instance 'person :name "adam")) # (slot-value p3 'counter) ;; => ERROR. No, our new slot isn't on the person class. (slot-value (find-class 'person) 'counter) (slot-exists-p uu 'status) ;; 1 (make-instance 'person :name "eve") ;; # (slot-value (find-class 'person) 'counter) ;; 2 #+END_SRC * Libs ** [[http://cl.celwk.com/cl-gd.htm#copy-image][CL-GD]] *** scp al:/files/libgd-2.2.4.tar.gz /files *** cd /files *** tar xvf libgd-2.2.4.tar.gz *** cd libgd-2.2.4.tar *** [[https://github.com/libgd/libgd/blob/master/docs/INSTALL][libgd/docs/INSTALL]] *** ./configure If shows: Support for Zlib: yes Support for PNG library: no Support for JPEG library: no Support for WebP library: no Support for TIFF library: no Support for Freetype 2.x library: no Support for Fontconfig library: no Support for Xpm library: no Support for liq library: no Support for pthreads: yes Install them by apt-get or yum ... Google it *** make *** make install *** cd ~/Emacs/quicklisp/dists/quicklisp/software/cl-gd-20171130-git/ *** make cl-gd-glue.so ** [[https://github.com/fukamachi/woo][Woo]] *** If install fail, miss `libev', then: **** yum install libev * History ** deep *** deep-cars *** deep-list-items *** deep-nth *** deep-remove-if *** deep-filter *** deep-parallel * Task **