* 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
**