Simplify and clean up the Elisp programming section

This commit is contained in:
Gerard Vermeulen 2024-05-08 13:13:09 +02:00
parent 9f00212781
commit 6c0cded371
1 changed files with 32 additions and 268 deletions

View File

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