Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 195 lines (147 sloc) 8.186 kb
a174f97 @tpapp Still trying to fix formatting on github.
authored
1 #+TITLE: =let+=: destructuring extension of =let*=
2 #+AUTHOR: Tamás K. Papp
3
4 This library implements the =let+= macro, which is a dectructuring
5 extension of =let*=.
6
7 * Highlights
8
9 - clean, consistent syntax and small implementation (less than 300 LOC, not counting tests)
10
11 - placeholder macros allow editor hints and syntax highlighting
12
eb09054 @tpapp Brought the README up to date.
authored
13 - =&ign= for ignored values (in forms where that makes sense)
a174f97 @tpapp Still trying to fix formatting on github.
authored
14
15 - very easy to extend
16
17 * Similar libraries
18
19 This library was inspired by Gary King's excellent [[http://common-lisp.net/project/metabang-bind/][metabang-bind]]. I
de54e85 @tpapp Minor changes to documentation, added example about destructuring lists.
authored
20 have been using the latter for years now, but at some point I decided
21 to write a library of my own, aiming for a cleaner syntax, more
22 concise implementation and a more consistent interface (whether I have
23 succeeded is of course a matter of judgement --- try [[http://common-lisp.net/project/metabang-bind/][metabang-bind]] to
24 see if you like it better).
a174f97 @tpapp Still trying to fix formatting on github.
authored
25
26 In my opinion the main advantages of this library, compared to
27 [[http://common-lisp.net/project/metabang-bind/][metabang-bind]], are the placeholder macros which provide editor hints
28 and the more consistent syntax of destructuring forms. In particular,
29 when both read-write and read-only forms are available the latter
30 always have the =-r/o= suffix, =&flet= and =&labels= resemble the
31 Common Lisp syntax more closely, and the library should be easier to
32 extend.
33
34 You can find other pattern matching libraries on [[http://www.cliki.net/pattern%20matching][cliki]].
35
36 * Syntax
37
38 #+BEGIN_SRC lisp
39 let+ ({binding}*) body*
40 #+END_SRC
41 where
42 #+BEGIN_SRC lisp
43 binding ::= symbol || (form [init-form])
44 #+END_SRC
45
46 =LET+= is recursive: each binding is in the scope of the previous
eb09054 @tpapp Brought the README up to date.
authored
47 ones. Forms ignore =&ign= variables (where applicable).
a174f97 @tpapp Still trying to fix formatting on github.
authored
48
49 ** Built-in forms
50
eb09054 @tpapp Brought the README up to date.
authored
51 Forms which provide both read-write and read-only access are available as =&form= and =&form-r/o=. The first one always uses symbol macros, so you can use =setf=. The second one reads the values at the beginning of the list from value: you can change these variables after that without having any effect on the original value. Read-only forms may also provide a slight increase in speed, and promote good style --- you can use them to signal that you will not change the original structure.
a174f97 @tpapp Still trying to fix formatting on github.
authored
52
eb09054 @tpapp Brought the README up to date.
authored
53 The following forms are defined:
a174f97 @tpapp Still trying to fix formatting on github.
authored
54
55 - =var=, =(var)=, =(var value)= :: These behave just like they do in =let*=.
de54e85 @tpapp Minor changes to documentation, added example about destructuring lists.
authored
56
eb09054 @tpapp Brought the README up to date.
authored
57 - =(list value)= :: When =list= is not recognized as any of the forms below, it is simply destructured using =destructuring-bind=. =&ign= are ignored. Example:
de54e85 @tpapp Minor changes to documentation, added example about destructuring lists.
authored
58 #+BEGIN_SRC lisp
eb09054 @tpapp Brought the README up to date.
authored
59 (let+ (((a (b &optional (c 3)) &ign &key (d 1 d?)) '(1 (2) 7 :d 4)))
de54e85 @tpapp Minor changes to documentation, added example about destructuring lists.
authored
60 (list a b c d d?)) ; => (1 2 3 4 T)
61 #+END_SRC
a174f97 @tpapp Still trying to fix formatting on github.
authored
62
eb09054 @tpapp Brought the README up to date.
authored
63 - =((&slots slot*) value)=, also =&slots-r/o= :: Similarly to =with-slots=, each =slot= has the syntax =variable= or =(variable)= (for these, the variable name is also used for the slot name) or =(variable slot-name)=. =&slots-r/o= provides read-only bindings.
a174f97 @tpapp Still trying to fix formatting on github.
authored
64
65 Example:
e0f0e82 @tpapp testing formatting.
authored
66 #+BEGIN_SRC lisp
b069fba @tpapp Wrote README.
authored
67 (defclass foo-class ()
68 ((a :accessor a :initarg :a)
69 (b :accessor b-accessor :initarg :b)))
70
71 (let+ (((&slots a (my-b b)) (make-instance 'foo-class :a 1 :b 2)))
72 (list a my-b)) ; => (1 2)
e0f0e82 @tpapp testing formatting.
authored
73 #+END_SRC
a174f97 @tpapp Still trying to fix formatting on github.
authored
74
eb09054 @tpapp Brought the README up to date.
authored
75 - =((&accessors accessor*) value)=, also =&accessors-r/o= :: Syntax similar to =&slots=, but uses accessors. Continuing the example above:
a174f97 @tpapp Still trying to fix formatting on github.
authored
76 #+BEGIN_SRC lisp
77 (let+ (((&accessors a (b b-accessor)) (make-instance 'foo-class :a 1 :b 2)))
78 (list a b)) ; => (1 2)
79 #+END_SRC
80
eb09054 @tpapp Brought the README up to date.
authored
81 - =((&structure conc-name slot*) value)=, also =&structure-r/o= :: Slot access for structures. =Conc-name= is prepended to the accessors (you need to include the =-= if there is one). Example:
a174f97 @tpapp Still trying to fix formatting on github.
authored
82 #+BEGIN_SRC lisp
83 (defstruct foo-struct c d)
84 (let+ (((&structure foo-struct- c (my-d d)) (make-foo-struct :c 3 :d 4)))
85 (list c my-d)) ; => (3 4)
86 #+END_SRC
87
eb09054 @tpapp Brought the README up to date.
authored
88 - =((&values value*) form)= :: Similar to =multiple-value-bind=. =&ign= are ignored. Example:
a174f97 @tpapp Still trying to fix formatting on github.
authored
89 #+BEGIN_SRC lisp
eb09054 @tpapp Brought the README up to date.
authored
90 (let+ (((&values a &ign b) (values 1 2 3)))
a174f97 @tpapp Still trying to fix formatting on github.
authored
91 (list a b)) ; => (1 3)
92 #+END_SRC
93
94 - =(array value)= (only read-only version) :: The array is
eb09054 @tpapp Brought the README up to date.
authored
95 destructured to the given elements, =&ign= are ignored. Indexes
a174f97 @tpapp Still trying to fix formatting on github.
authored
96 use row-major access, determined at macroexpansion time.
97 Example:
98 #+BEGIN_SRC lisp
eb09054 @tpapp Brought the README up to date.
authored
99 (let+ ((#(a &ign b) (vector 1 2 3)))
a174f97 @tpapp Still trying to fix formatting on github.
authored
100 (list a b)) ; => (1 3)
101 #+END_SRC
102
eb09054 @tpapp Brought the README up to date.
authored
103 - =((&array-elements (variable subscript*)*) value)=, also =&array-elements-r/o= :: Array elements with given subscripts are assigned to the variables. Example:
a174f97 @tpapp Still trying to fix formatting on github.
authored
104 #+BEGIN_SRC lisp
105 (let+ (((&array-elements (a 0 1)
106 (b 2 0))
107 #2A((0 1)
108 (2 3)
109 (4 5))))
110 (list a b)) ; => (1 4)
111 #+END_SRC
112
eb09054 @tpapp Brought the README up to date.
authored
113 - =((&flet name lambda-list forms*))=, also =&labels= :: Function bindings. These have no value form. =&labels= allows the function to refer to itself -- note that since =let+= is always recursive, this is the only difference between the two forms. Example:
a174f97 @tpapp Still trying to fix formatting on github.
authored
114 #+BEGIN_SRC lisp
115 (let+ (((&flet add2 (x)
116 (+ x 2))))
117 (add2 5)) ; => 7
118 #+END_SRC
119
eb09054 @tpapp Brought the README up to date.
authored
120 - =((&plist (variable key [default])*)=, also =&plist-r/o= :: Access to property lists. When =key= is not given, =variable= is used instead, and =default= is used if the element does not exist in the value (note that default may be evaluated multiple times when using the read-write form which uses =symbol-macrolet=). Example:
a174f97 @tpapp Still trying to fix formatting on github.
authored
121 #+BEGIN_SRC lisp
122 (let+ (((&plist a (my-b b) (c nil 3)) '(a 1 b 2)))
123 (list a my-b c)) ; => (1 2 3)
124 #+END_SRC
125
eb09054 @tpapp Brought the README up to date.
authored
126 - =(((&hash-table (variable key [default])*)=, also =&hash-table-r/o= :: Access to the elements of hash tables, the semantics is the same as =&plist=.
127
128 - =(&complex real imaginary)= :: Destructures complex numbers.
129
130 ** Nesting
131
2849cc3 @tpapp Added clarification about nesting.
authored
132 You can nest =let+= expressions when it makes sense (it doesn't always, especially for read/write slots, the read only form should work). For example,
eb09054 @tpapp Brought the README up to date.
authored
133 #+BEGIN_SRC lisp
134 (let+ ((#((&complex a b)) (vector (complex 1 2))))
135 (list a b))
136 #+END_SRC
137 should destructure the complex number that is the single element in the vector.
138
139 If you find that =let+= does not nest properly, please report it as a bug.
a174f97 @tpapp Still trying to fix formatting on github.
authored
140
141 ** Convenience macros
142
eb09054 @tpapp Brought the README up to date.
authored
143 - =(defun+ name (argument*) form*)=, also =(lambda (argument*) form*)= :: Work like =defun= and =lambda=, but arguments are destructured using =let+=. Example:
a174f97 @tpapp Still trying to fix formatting on github.
authored
144 #+BEGIN_SRC lisp
145 (defun+ foo ((&plist a b c) #(d e))
146 (list a b c d e))
147
148 (foo '(a 1 b 2 c 3) #(4 5)) ; => (1 2 3 4 5)
149 #+END_SRC
eb09054 @tpapp Brought the README up to date.
authored
150 See also =&labels+= and =&lambda+=.
a174f97 @tpapp Still trying to fix formatting on github.
authored
151
eb09054 @tpapp Brought the README up to date.
authored
152 - =define-structure-let+= :: Can be used to provide destructuring forms for structures.
a174f97 @tpapp Still trying to fix formatting on github.
authored
153
eb09054 @tpapp Brought the README up to date.
authored
154 ** Other forms
155
156 - =(&once-only symbols ...)= and =(&with-gensyms symbols)= are useful for writing macros.
a174f97 @tpapp Still trying to fix formatting on github.
authored
157
158 * Extensions
159
160 Extending =let-plus= is very easy: if you want to use a form that
161 resembles a list, you just have to define a method for
162 =let+-expansion-for-list=. There is a macro that helps you with that,
163 called =define-let+-expansion=. If the library didn't have
eb09054 @tpapp Brought the README up to date.
authored
164 =&complex=, we could define destructuring for the form like this:
a174f97 @tpapp Still trying to fix formatting on github.
authored
165
166 #+BEGIN_SRC lisp
eb09054 @tpapp Brought the README up to date.
authored
167 (define-let+-expansion (&complex (x y))
168 "Access real and imaginary part of the value. Read-only."
169 `(let ((,x (realpart ,value))
170 (,y (imagpart ,value)))
a174f97 @tpapp Still trying to fix formatting on github.
authored
171 ,@body))
172 #+END_SRC
173 Some highlights:
174
eb09054 @tpapp Brought the README up to date.
authored
175 - this macro defines a "placeholder" macro =&complex= that should
a174f97 @tpapp Still trying to fix formatting on github.
authored
176 help with editor hints, but has no other purpose (it is not used in
177 the expansion),
178 - the macro is anaphoric, capturing =value= (the value form) and
179 =body= (the body inside the =let+= form), you can customize both of
180 this using keyword arguments,
181 - unless required otherwise, =value= is wrapped in =once-only=
eb09054 @tpapp Brought the README up to date.
authored
182 preventing multiple evaluations of the same form. See the arguments =:uses-value?= and =:once-only?= for =define-let+-expansion=.
a174f97 @tpapp Still trying to fix formatting on github.
authored
183
184 If you want to extend =let+= with forms that are not lists (eg like
185 the array syntax above), have a look at =let+-expansion=.
186
187 * Reporting bugs
188
68343eb @tpapp Added link to issues.
authored
189 Please open an [[https://github.com/tpapp/let-plus/issues][issue]] on Github for bugs. Extensions are also welcome,
a174f97 @tpapp Still trying to fix formatting on github.
authored
190 either as forks or small code snippets submitted as issues. Wishlist
191 items are also welcome!
192
193 I ask you not to report bugs via e-mail if you can avoid it. Tracking
194 bugs on Github makes it less likely that they get lost.
Something went wrong with that request. Please try again.