Simplify and clean up the Elisp programming section
This commit is contained in:
parent
9f00212781
commit
6c0cded371
300
README.org
300
README.org
@ -648,11 +648,6 @@ for technical information.
|
||||
#+caption: Window management variables.
|
||||
#+name: lst:3rd-window-management
|
||||
#+begin_src emacs-lisp -n :results none
|
||||
;; (info "(emacs) Bug Reference")
|
||||
(defvar bug-reference-url-format
|
||||
"https://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s"
|
||||
"Setting this as a file local variable enables `bug-reference-mode'")
|
||||
|
||||
;; (info "(elisp) Displaying Buffers")
|
||||
;; (info "(emacs) Window Choice")
|
||||
;; (describe-function 'display-buffer)
|
||||
@ -5329,8 +5324,39 @@ Here is a list of links describing how to program and debug [[info:elisp#Top][Em
|
||||
Ref. [cite:@Monnier.ACM-PL.4.1] exposes the evolution of Emacs Lisp and explains
|
||||
important Emacs Lisp idioms.
|
||||
|
||||
*** [[info:emacs#Bug Reference][Bug Reference Mode (info)]]
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: sec:bug-reference-mode
|
||||
:END:
|
||||
|
||||
Listing [[lst:bug-reference-mode]] configures ~bug-reference-mode~ for use with the
|
||||
[[https://debbugs.gnu.org/][GNU Bug Tracker]].
|
||||
|
||||
#+caption[Setup ~bug-reference-mode~]:
|
||||
#+caption: Setup ~bug-reference-mode~.
|
||||
#+name: lst:bug-reference-mode
|
||||
#+begin_src emacs-lisp -n :results silent
|
||||
;; (info "(emacs) Bug Reference")
|
||||
(defvar bug-reference-url-format
|
||||
"https://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s"
|
||||
"Setting this as a file local variable enables `bug-reference-mode'")
|
||||
#+end_src
|
||||
|
||||
*** [[info:elisp#Debugging][Debugging Emacs Lisp (info)]]
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: sec:debugging
|
||||
:END:
|
||||
|
||||
GAV: I fail to instrument the functions from the [[https://www.emacswiki.org/emacs/SourceLevelDebugger][source level debugger (edebug)]]
|
||||
wiki entry as in [[info:elisp#Edebug][Edebug (info)]].
|
||||
|
||||
*** [[https://www.masteringemacs.org/article/evaluating-elisp-emacs][Evaluating Elisp in Emacs]]
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: sec:elisp-evaluation
|
||||
:END:
|
||||
|
||||
Listing [[lst:setup-ielm][setup ielm]] configures the [[https://wikemacs.org/wiki/IELM][Interactive Emacs Lisp Mode]] for better
|
||||
interoperability with [[https://smartparens.readthedocs.io/en/latest/][Smartparens]]: get help on the key bindings by means of
|
||||
interoperability with [[https://smartparens.readthedocs.io/en/latest/][smartparens]]: get help on the key bindings by means of
|
||||
src_emacs-lisp[:results silent]{(describe-function 'ielm)}.
|
||||
|
||||
#+caption[Setup =ielm=]:
|
||||
@ -5341,268 +5367,6 @@ src_emacs-lisp[:results silent]{(describe-function 'ielm)}.
|
||||
(setopt ielm-dynamic-return nil))
|
||||
#+end_src
|
||||
|
||||
*** [[https://lists.gnu.org/archive/html/emacs-devel/2023-11/msg00764.html][Benchmarking Emacs Lisp]] :noexport:
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: sec:benchmarking
|
||||
:header-args:emacs-lisp: :exports code :tangle no
|
||||
:END:
|
||||
|
||||
The following snippets present and use a [[https://lists.gnu.org/archive/html/emacs-devel/2023-11/msg00764.html][copy]] of João Távora's code to benchmark
|
||||
Emacs Lisp forms.
|
||||
|
||||
#+caption[Define macro to benchmark groups of forms]:
|
||||
#+caption: Define macro to benchmark groups of forms.
|
||||
#+name: lst:benchmark-group
|
||||
#+begin_src emacs-lisp -n :results silent
|
||||
(defvar joaot/bench-group-name nil)
|
||||
(defvar joaot/setup-form nil)
|
||||
(defvar joaot/timings-alist nil)
|
||||
(defvar joaot/repetitions nil)
|
||||
|
||||
(defmacro joaot/with-benchmark-group (bench-name
|
||||
setup-form
|
||||
repetitions
|
||||
&rest body)
|
||||
(declare (indent 1))
|
||||
(let ((f `(alist-get ,bench-name joaot/timings-alist nil nil #'equal)))
|
||||
`(let ((joaot/bench-group-name ,bench-name)
|
||||
(joaot/setup-form ',setup-form)
|
||||
(joaot/repetitions ,repetitions))
|
||||
(setf ,f (list))
|
||||
,@body
|
||||
(cl-loop with sorted = (setf ,f (cl-sort ,f #'< :key #'cadr))
|
||||
with fastest = (cadr (car sorted))
|
||||
for i from 0
|
||||
for res in sorted
|
||||
for prev-time = time
|
||||
for (_n time . more) = res
|
||||
do (setcdr res
|
||||
(cl-list* (if (eq time fastest) "FASTEST"
|
||||
(format "%2.1fx %sSLOWER"
|
||||
(/ time fastest)
|
||||
(if (= i 1) ""
|
||||
(format "(rel %2.1fx) "
|
||||
(/ time prev-time)))))
|
||||
time
|
||||
more)))
|
||||
joaot/timings-alist)))
|
||||
#+end_src
|
||||
|
||||
#+caption[Define macro to benchmark forms]:
|
||||
#+caption: Define macro to benchmark forms.
|
||||
#+name: lst:benchmark-form
|
||||
#+begin_src emacs-lisp -n :results silent
|
||||
(defmacro joaot/bench (form)
|
||||
`(cl-progv
|
||||
(mapcar #'car joaot/setup-form)
|
||||
(mapcar #'eval (mapcar #'cdr joaot/setup-form))
|
||||
(let ((res
|
||||
(benchmark-call (prog1
|
||||
(,(if (native-comp-available-p)
|
||||
'native-compile
|
||||
'byte-compile)
|
||||
'(lambda () ,form))
|
||||
(garbage-collect))
|
||||
joaot/repetitions))
|
||||
(group-name joaot/bench-group-name)
|
||||
(bench-name ',(car form)))
|
||||
(push (cons bench-name res)
|
||||
(alist-get group-name joaot/timings-alist nil nil #'equal)))))
|
||||
#+end_src
|
||||
|
||||
#+caption[Define benchmark helper functions]:
|
||||
#+caption: Define benchmark helper functions.
|
||||
#+name: lst:benchmark-helpers
|
||||
#+begin_src emacs-lisp -n :results silent
|
||||
(defun bench-cl-loop-list (l)
|
||||
(cl-loop for e in l thereis (identity e)))
|
||||
|
||||
(defun bench-cl-loop-vec (v)
|
||||
(cl-loop for e across v thereis (identity e)))
|
||||
|
||||
(defun bench-cl-some (seq)
|
||||
(cl-some #'identity seq))
|
||||
|
||||
(defun bench-seq-some (seq)
|
||||
(seq-some #'identity seq))
|
||||
#+end_src
|
||||
|
||||
#+caption[Benchmark =some= operations on big lists]:
|
||||
#+caption: Benchmark =some= operations on big lists.
|
||||
#+name: lst:benchmark-some-big-lists
|
||||
#+begin_src emacs-lisp -n :eval no-export :results pp silent
|
||||
(joaot/with-benchmark-group "\"some\" operation, big lists"
|
||||
((list1 . (make-list 100000 nil)))
|
||||
100
|
||||
(joaot/bench (bench-cl-loop-list list1))
|
||||
(joaot/bench (cl-some #'identity list1))
|
||||
(joaot/bench (seq-some #'identity list1)))
|
||||
#+end_src
|
||||
|
||||
#+caption[Benchmark =some= operations on small lists]:
|
||||
#+caption: Benchmark =some= operations on small lists.
|
||||
#+name: lst:benchmark-some-small-lists
|
||||
#+begin_src emacs-lisp -n :eval no-export :results pp silent
|
||||
(joaot/with-benchmark-group "\"some\" operation, small lists"
|
||||
((list1 . (make-list 10 nil)))
|
||||
100000
|
||||
(joaot/bench (bench-cl-loop-list list1))
|
||||
(joaot/bench (cl-some #'identity list1))
|
||||
(joaot/bench (seq-some #'identity list1)))
|
||||
#+end_src
|
||||
|
||||
#+caption[Accumulated results of benchmark examples]:
|
||||
#+caption: Accumulated results of benchmark examples.
|
||||
#+name: lst:benchmark-example
|
||||
#+header: :wrap "src emacs-lisp -n"
|
||||
#+begin_src emacs-lisp -n :eval no-export :exports both :results pp
|
||||
(joaot/with-benchmark-group "destructuring"
|
||||
((list1 . (make-list 3 0)))
|
||||
100000
|
||||
(joaot/bench (pcase-let ((`(,a ,b ,c) list1)) (+ a b c)))
|
||||
(joaot/bench (cl-destructuring-bind (a b c) list1 (+ a b c)))
|
||||
(joaot/bench (seq-let (a b c) list1 (+ a b c))))
|
||||
#+end_src
|
||||
|
||||
#+caption[Accumulated results of benchmark examples]:
|
||||
#+caption: Accumulated results of benchmark examples.
|
||||
#+name: lst:benchmark-example-results
|
||||
#+RESULTS: lst:benchmark-example
|
||||
#+begin_src emacs-lisp -n
|
||||
(("\"some\" operation, small lists" (cl-some "FASTEST" 0.027944 0 0.0)
|
||||
(seq-some "2.6x SLOWER" 0.073602 0 0.0)
|
||||
(bench-cl-loop-list "134.4x (rel 51.0x) SLOWER" 3.7544939999999998
|
||||
12 2.701254000000006))
|
||||
("\"some\" operation, big lists" (cl-some "FASTEST" 0.242062 0 0.0)
|
||||
(seq-some "2.5x SLOWER" 0.614304 0 0.0)
|
||||
(bench-cl-loop-list "14.5x (rel 5.7x) SLOWER" 3.505071 0 0.0))
|
||||
("destructuring"
|
||||
(cl-destructuring-bind "FASTEST" 0.013874999999999998 0 0.0)
|
||||
(pcase-let "1.2x SLOWER" 0.016648 0 0.0)
|
||||
(seq-let "2.8x (rel 2.4x) SLOWER" 0.039485 0 0.0)))
|
||||
#+end_src
|
||||
|
||||
*** [[info:elisp#Debugging][Debugging Emacs Lisp (info)]]
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: sec:debugging
|
||||
:header-args:emacs-lisp: :exports code :tangle no
|
||||
:END:
|
||||
|
||||
Listing [[lst:example-edebug][edebug example]] from the [[https://www.emacswiki.org/emacs/SourceLevelDebugger][source level debugger (edebug)]] wiki entry is a
|
||||
minimal example of how to use =edebug=:
|
||||
1. Type {{{kbd(C-c ')}}} to open its =org-src-mode= buffer.
|
||||
2. Type {{{kbd(C-M-x)}}} with point in =foo=.
|
||||
3. Type {{{kbd(C-M-x)}}} with point in =bar=.
|
||||
4. Evaluate =(foo)=.
|
||||
5. Type {{{kbd(C-u C-M-x)}}} with point in =bar=.
|
||||
6. Evaluate =(foo)=.
|
||||
7. Type the space bar to step through =bar=.
|
||||
Note: I fail to instrument functions as in [[info:elisp#Edebug][Edebug (info)]].
|
||||
|
||||
#+caption[Example for =edebug=]:
|
||||
#+caption: Example for =edebug=.
|
||||
#+name: lst:example-edebug
|
||||
#+begin_src emacs-lisp -n :exports code :results silent
|
||||
(defun foo ()
|
||||
(interactive)
|
||||
(bar))
|
||||
|
||||
(defun bar ()
|
||||
(let ((a 5)
|
||||
(b 7))
|
||||
(message "%d" (+ a b))))
|
||||
#+end_src
|
||||
|
||||
*** [[https://emacs.stackexchange.com/questions/2129/why-is-let-faster-with-lexical-scope][Disassemble dynamical and lexical scope]] :noexport:
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: sec:disassemble-dynamical-lexical-scope
|
||||
:header-args:emacs-lisp: :exports code :tangle no
|
||||
:END:
|
||||
|
||||
Listing [[lst:disassemble-lexical-scope][lexical scope disassembly]] and [[lst:disassemble-dynamical-scope][dynamical scope disassembly]] disassemble
|
||||
identical code in case of respectively lexical and dynamical scope. Listing
|
||||
[[lst:disassemble-lexical-scope-results][lexical scope disassembly results]] and [[lst:disassemble-dynamical-scope-results][dynamical scope disassembly results]] show
|
||||
the respective results.
|
||||
|
||||
The link [[https://emacs.stackexchange.com/questions/61754/how-can-i-enable-lexical-binding-for-elisp-code-in-org-mode][how to enable lexical scope for Emacs Lisp in org-mode source blocks]]
|
||||
explains all possibilities of disabling or enabling lexical scope.
|
||||
|
||||
#+caption[Disassemble lexical scope]:
|
||||
#+caption: Disassemble lexical scope.
|
||||
#+name: lst:disassemble-lexical-scope
|
||||
#+header: :wrap "src text -n"
|
||||
#+begin_src emacs-lisp -n :exports both :lexical t :results value
|
||||
(with-temp-buffer
|
||||
(disassemble (lambda (n)
|
||||
"Demonstrate lexical scope."
|
||||
(let* ((lower most-negative-fixnum)
|
||||
(upper most-positive-fixnum)
|
||||
(sum (+ lower upper)))
|
||||
(expt sum n)))
|
||||
(current-buffer))
|
||||
(buffer-substring-no-properties (point-min) (point-max)))
|
||||
#+end_src
|
||||
|
||||
#+caption[Disassemble lexical scope results]:
|
||||
#+caption: Disassemble lexical scope results.
|
||||
#+name: lst:disassemble-lexical-scope-results
|
||||
#+RESULTS: lst:disassemble-lexical-scope
|
||||
#+begin_src text -n
|
||||
byte code:
|
||||
doc: Demonstrate lexical scope. ...
|
||||
args: (arg1)
|
||||
0 varref most-negative-fixnum
|
||||
1 varref most-positive-fixnum
|
||||
2 stack-ref 1
|
||||
3 stack-ref 1
|
||||
4 plus
|
||||
5 constant expt
|
||||
6 stack-ref 1
|
||||
7 stack-ref 5
|
||||
8 call 2
|
||||
9 return
|
||||
#+end_src
|
||||
|
||||
#+caption[Disassemble dynamical scope]:
|
||||
#+caption: Disassemble dynamical scope.
|
||||
#+name: lst:disassemble-dynamical-scope
|
||||
#+header: :wrap "src text -n"
|
||||
#+begin_src emacs-lisp -n :exports both :results value
|
||||
(with-temp-buffer
|
||||
(disassemble (lambda (n)
|
||||
"Demonstrate lexical scope."
|
||||
(let* ((lower most-negative-fixnum)
|
||||
(upper most-positive-fixnum)
|
||||
(sum (+ lower upper)))
|
||||
(expt sum n)))
|
||||
(current-buffer))
|
||||
(buffer-substring-no-properties (point-min) (point-max)))
|
||||
#+end_src
|
||||
|
||||
#+caption[Disassemble dynamical scope results]:
|
||||
#+caption: Disassemble dynamical scope results.
|
||||
#+name: lst:disassemble-dynamical-scope-results
|
||||
#+RESULTS: lst:disassemble-dynamical-scope
|
||||
#+begin_src text -n
|
||||
byte code:
|
||||
doc: Demonstrate lexical scope.
|
||||
args: (n)
|
||||
0 varref most-negative-fixnum
|
||||
1 varbind lower
|
||||
2 varref most-positive-fixnum
|
||||
3 varbind upper
|
||||
4 varref lower
|
||||
5 varref upper
|
||||
6 plus
|
||||
7 varbind sum
|
||||
8 constant expt
|
||||
9 varref sum
|
||||
10 varref n
|
||||
11 call 2
|
||||
12 unbind 3
|
||||
13 return
|
||||
#+end_src
|
||||
|
||||
*** [[http://yummymelon.com/devnull/writing-better-elisp-docstrings.html][Writing Better Elisp Docstrings]]
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: sec:describe-function-at-point
|
||||
|
Loading…
Reference in New Issue
Block a user