* Files https://lispcookbook.github.io/cl-cookbook/files.html http://cl.com/14.files-and-file-io.htm ** 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" (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" (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 ** Stream #+BEGIN_SRC lisp (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)" (with-input-from-string (s "1.23") (read s)) => 1.23 (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 * String ** JS Regular Expression ?: is for non capturing group ?= is for positive look ahead ?! is for negative look ahead ?<= is for positive look behind ? without reading it read-char-no-hang => don't wait for it unread-char => push a char back * Data Structures ** Collection http://cl.com/11.collections.htm vector -> sequence list -> sequence copy-seq copy-list copy-tree *** Get #+begin_src lisp (elt '(1 2 3) 1) => (elt #(1 2 3) 1) => 2 (setf (elt *x* 0) 10) (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 *** 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 (recursive) replace item: 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 :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 #+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 (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 ** 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 (set-difference '(1 2 3) '(2 3 5)) => (1) (set-exclusive-or '(1 2 3) '(2 3 5)) => (5 1) 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 *** Lookup Tables: Alists and Plists :list:alist:plist: http://cl.com/13.beyond-lists-other-uses-for-cons-cells.htm ASSOC :key :test ASSOC-IF ASSOC-IF-NOT RASSOC RASSOC-IF RASSOC-IF-NOT #+BEGIN_SRC lisp (assoc "a" '(("a" . 1) ("b" . 2) ("c" . 3)) :test #'string=) => ("a" . 1) (assoc 'a '((a . 10) (a . 1) (b . 2) (c . 3))) => (A . 10) (acons 'new-key 'new-value alist) => (cons (cons 'new-key 'new-value) alist) ;; Not update alist (setf alist (acons 'new-key 'new-value alist)) => (push (cons 'new-key 'new-value) alist) ;; Update (pairlis '(a b c) '(1 2 3)) => ((C . 3) (B . 2) (A . 1)) ;; part #+END_SRC [[Plist]] [[ Cons Cells]] get getf ** Symbols *** Plist #+BEGIN_SRC lisp (symbol-name 'abc) ;=> "ABC" (write-to-string 'abc) ;=> "abc" Depeneds on *print-case* (read-from-string "Can") ;=> can (a symbol 'can) (setf (get 'alizarin 'color) 'red) ;;=> RED (get 'alizarin 'color) ;;=> RED (get 'symbol 'key) === (getf (symbol-plist 'symbol) 'key) (setf (get 'some-symbol 'my-key) "information") (defparameter *plist* ()) (setf (getf *plist* :a) 1) => 1 ,*plist* => (:A 1) (setf (getf *plist* :a) 2) => 2 ,*plist* => (:A 2) (boundp 'var) (symbol-value 'var) ;;SETFable (fboundp 'func) (symbol-function 'func) ;;SETFable (makunbound 'var-or-func) #+END_SRC * Macros ** Cons Cells :list:cons: rotatef (rotatef a b) a <=> b shiftf (shiftf a b 10) a => b, b => 10, return origin a #+BEGIN_SRC lisp (boundp 'var) (symbol-value 'var) ;;SETFable, can be either function or variable (fboundp 'func) (symbol-function 'func) ;;SETFable (makunbound 'var-or-func) ;; multiple value-* : (multiple-value-list (get-decoded-time)) => (59 40 7 ...) (multiple-value-list (values 1 2 3)) => (1 2 3) (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) (apply #'values '(1 2 3 4)) => (values 1 2 3 4) 1|2|3|4 ;; 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)) ;;==> (:X 3 :Y 2 :Z 1 :WHOLE (:Z 1 :Y 2 :X 3)) #+END_SRC ** [[http://clhs.lisp.se/Body/02_d.htm][Standard Macro Characters]] *** [[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 ** [[http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_1.htm][(defin-symbol-macro)]] (defvar name "Can EriK") name => (define-symbol-macro ln (length name)) ln => ln 8 can> (setf name "Can") "Can" => ln 3 (define-symbol-macro *max* (car (sort (copy-list lst) #'>))) *max* => Get max of lst dynamically * Function (setf (symbol-function 'xx) #'(lambda ...)) == (defun xx (...)) #'memorize #'compose/pipe #'curry #'complement * Algorithm ** 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 * 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]] #+BEGIN_SRC lisp (step code) (trace func-name) (untrace func-name) ;; 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 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 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 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: C-c C-v TAB (slime-inspect-presentation-at-point POINT) ;; OR right click the object and select Inspect :*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 #+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 * Shell ** Environmental Variable #+BEGIN_SRC lisp ;; SHELL environment: ;; WHO="Savior Can" sbcl ;; * (posix-getenv "WHO") => "Savior Can" (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 来安装!!例如: (ql:quickload :cepl) (ql:quickload :varjo) ** SLIME Keys 'slime-who-calls #+BEGIN_SRC elisp ;; Compile Load ("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") ;; 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) 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 ** 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) #+END_SRC ** Server AliYun root@39.99.171.57 1***2Can * Object Reorientation #+BEGIN_SRC lisp (find-method generic-function method-qualifiers specializers &optional errorp) (function-keywords method) => keys, allow-other-keys-p ;; only for method, exclude normal function (sb-introspect:function-lambda-list fn) (function-lambda-expression fn) ;; Show defined by yourself, exclude internal functions (e.g mapcar) #+END_SRC * My Styles ** Functions which return a function should be named end with ~ (e.g memorize~ pipe~ is~ alaways~) Most are with arguments of functions ** Recursive Functions end with + (e.g find-if+ list+) * TODO [0/2] 1. [ ] `funargs' Get function args separated by types: default, key, rest * Sat Dec 21 22:16:13 2019 2. [ ] 3. [ ] Create a function of the same name with a funcation variable * (defvar fn (^(...))) (defun+ fn) => (fn ...)