-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdocstrings.lisp
331 lines (219 loc) · 8.73 KB
/
docstrings.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
(uiop:define-package :more-docstrings
(:use :cl))
(in-package :more-docstrings)
#|
Add more documentation and add examples to the docstrings.
Now, when we read a function documentation from our editor or with the
built-in `documentation` function, we can learn more about it, and see
examples. We have less the need to reach for external resources.
The goal is still to ease the first contact of newcomers with CL.
For example, give examples on how to use MAP, MAPCAR, MAPCAN.
XXX: gotchas
- if we quickload :ciel twice, the docstrings
are appended twice too :S The hash-table cache doesn't help in that
case.
- we are modifying the symbols in the :cl package, not the ones in :ciel.
|#
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; One function to do the job:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar *docstrings-cache* (make-hash-table)
"Cache the original docstring of functions and macros we are augmenting.
Mainly to ease our tests at the REPL.")
(defun documentation-with-cache (symbol &optional (doc-type 'function))
(let ((cached (gethash symbol *docstrings-cache*)))
(if cached
cached
(let ((doc (documentation symbol doc-type)))
(setf (gethash symbol *docstrings-cache*)
;; don't store a NIL docstring.
(or doc ""))
doc))))
(defun docstring-append (symbol s &optional (doc-type 'function))
"Add S to the docstring of SYMBOL (to designate a function or a macro).
DOC-TYPE is the required argument of DOCUMENTATION, by default 'function (for functions and macros), otherwise use 'variable."
(let ((doc (documentation-with-cache symbol doc-type)))
(setf (documentation symbol doc-type)
(str:concat doc s))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Now use it.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Variables
(docstring-append '*default-pathname-defaults* "
An implementation-dependent pathname, typically in the working directory that was current when Common Lisp was started up.
Read more:
- https://cl-community-spec.github.io/pages/002adefault_002dpathname_002ddefaults_002a.html"
'variable)
;;; mapcar
(docstring-append 'mapcar "
For example:
(mapcar #'+ '(1 2 3) '(10 20 30)) ;; => (11 22 33)
(mapcar (lambda (x)
(format t \"~a is ~R~&\" x x))
'(1 2 3))
;; =>
1 is one
2 is two
3 is three
(NIL NIL NIL)
")
;;; mapcan
(docstring-append 'mapcan "
NCONC concatenates lists destructively.")
;;; sort
(docstring-append 'sort "
Since SORT is destructive, use COPY-LIST:
(setq mylist (list 1 3 2))
(sort (copy-list mylist) #'<)
See also STABLE-SORT.")
;;; loop
(docstring-append 'loop "
The basic LOOP structure is
(loop for x in (list x y z)
do …)
\"do\" is for side effects.
Use \"collect\" to return results:
(loop for x in (list 1 2 3)
collect (* x 10))
To iterate over arrays, use \"across\" instead of \"in\".
To iterate over hash-tables… try MAPHASH first :D
For many examples, see the CL Cookbook:
https://lispcookbook.github.io/cl-cookbook/iteration.html")
;;; maphash
(docstring-append 'maphash "
Example:
(maphash (lambda (key value)
(format t \"key is: ~a, value is: ~a~&\" key value))
(dict :a 'one))
;; => key is: A, value is: ONE")
;;; defun
(docstring-append 'defun "
Example:
(defun hello (name)
\"Say \\\"hello\\\" to NAME.\"
(format t \"Hello ~a!\" name))
Define named parameters with &key:
(defun hello (name &key lisper)
...)
and use it like so: (hello \"you\" :lisper t)
Key parameters are NIL by default. Give them another default value like this:
(defun hello (name &key (lisper t))
...)
Read more:
https://gigamonkeys.com/book/functions.html
https://lispcookbook.github.io/cl-cookbook/functions.html")
;;; defmacro
(docstring-append 'defmacro "Macros operate on code, which they see as lists of lists of symbols.
Macros, unlike functions, do not evaluate their arguments. They
expand (at compile time) into another piece of code, that will
eventually be evaluated.
First rule for macros: don't write a macro when a function can do.
Example macros: DEFUN LOOP SETF WITH-OPEN-FILE
See also: QUOTE BACKQUOTE GENSYM MACROEXPAND
Read more:
https://lispcookbook.github.io/cl-cookbook/macros.html
https://gigamonkeys.com/book/macros-standard-control-constructs.html
https://www.youtube.com/watch?v=ygKXeLKhiTI Little bits of Lisp video
")
;;; defclass
(docstring-append 'defclass "The macro defclass defines a new named class. It returns the new class object as its result.
Example:
(defclass living-being () ())
(defclass person (living-being)
((name
:initarg :name
:initform \"\"
:accessor name)
(lisper
:initarg :lisper
:initform nil
:accessor lisper
:documentation \"Set to non-nil if this person fancies Lisp.\")))
Slots are unbound by default, here we prefer them to be the empty string and nil.
An :accessor creates a generic method. You can have the same accessor name in different classes.
Create an instance of that class with MAKE-INSTANCE:
(make-instance 'person :name \"Alice\" :lisper t)
Define how to pretty-print an object with PRINT-OBJECT.
After we change a class definition (slots are modified, added or removed), we can control how an object is updated with UPDATE-INSTANCE-FOR-REDEFINED-CLASS.
Read more:
https://lispcookbook.github.io/cl-cookbook/clos.html
https://cl-community-spec.github.io/pages/defclass.html
")
;;; to be continued.
(docstring-append 'print-object "The generic function print-object writes the printed representation of object to stream. The function print-object is called by the Lisp printer; it should not be called by the user.
Example:
(defmethod print-object ((obj person) stream)
(print-unreadable-object (obj stream :type t :identity t)
(with-slots (name lisper) obj
(format stream \"~a, lisper: ~a\" name lisper))))
(make-instance 'person :name \"Alice\")
;; =>
#<PERSON Alice, lisper: NIL {1007277633}>
(1) (2) (3)
1 tells the reader that this object can't be read back in
2 is the object type
3 is the object identity (address).
Read more:
https://cl-community-spec.github.io/pages/print_002dobject.html
https://lispcookbook.github.io/cl-cookbook/clos.html#pretty-printing
")
(docstring-append 'defstruct "
Example:
(defstruct person
name age)
Creates the `make-person' constructor function, the `person-p' predicate as well as the `person-name' and `person-age' setf-able functions:
(person-name (make-person :name \"lisper\"))
;; => \"lisper\"
Read more:
- https://lispcookbook.github.io/cl-cookbook/data-structures.html#structures
- https://cl-community-spec.github.io/pages/defstruct.html")
(docstring-append 'defgeneric "
A generic function is a lisp function which is associated
with a set of methods and dispatches them when it's invoked. All
the methods with the same function name belong to the same generic
function.
The `defgeneric` form defines the generic function. If we write a
`defmethod` without a corresponding `defgeneric`, a generic function
is automatically created.
Example:
(defgeneric greet (obj)
(:documentation \"says hi\")
(:method (obj)
(format t \"Hi\")))
")
(docstring-append 'find "
Search for ITEM in SEQUENCE, return ITEM.
Example:
(find 20 '(10 20 30)) ;; => 20
(find \"foo\" '(\"abc\" \"foo\") :test #'string-equal) ;; => \"foo\"
See also: `find-if', `position', `search', `index', `elt'…
Read more:
- https://cl-community-spec.github.io/pages/find.html
- https://lispcookbook.github.io/cl-cookbook/data-structures.html")
(docstring-append 'with-open-file "
Example:
write to a file:
(with-open-file (f \"/path/to/file.txt\" :direction :output
:if-exists :supersede
:if-does-not-exist :create)
(write-sequence \"hello file\" f))
This binds a stream to the `f' variable and we write content to it.
You can read files with :direction :input as well as UIOP: uiop:read-file-string, uiop:read-file-lines etc.
Read more:
- https://lispcookbook.github.io/cl-cookbook/files.html
- https://cl-community-spec.github.io/pages/with_002dopen_002dfile.html
")
(docstring-append 'round "
See also:
- `fround', that returns the rounded value as a float
- `ceiling', `floor' and `truncate' (and their f… equivalent).
Read more:
- https://lispcookbook.github.io/cl-cookbook/numbers.html
- https://cl-community-spec.github.io/pages/floor.html")
#+ciel
(docstring-append 'function-cache:defcached "
Example:
(defcached (foo :timeout 10) (arg)
(sleep 3)
arg)
The functions's result is cached for 10 seconds, for the given argument. A second call returns immediately.")