source: project/wiki/eggref/4/list-bindings @ 29965

Last change on this file since 29965 was 29965, checked in by juergen, 8 years ago

list-bindings 1.7

File size: 11.1 KB
Line 
1[[tags: egg]]
2[[toc:]]
3
4== list-bindings
5
6This module provides some binding constructs, including a version of Common
7Lisp's destructuring-bind but with a shorter name, bind, and - as applications -
8define-macro, let-macro and letrec-macro. In all the macros defined
9here, pat is a pattern, i.e. a nested lambda-list and pattern variables
10are the symbols of the pattern.
11
12Contrary to the bindings egg, destructuring is only done for
13list expressions, which is sufficient for low-level macros.
14
15=== Programming interface
16
17==== list-bindings
18
19<procedure>(list-bindings)</procedure>
20
21shows the list of exported symbols.
22
23==== bind
24
25<syntax>(bind pat xpr . body)</syntax>
26
27binds pattern variables of the pattern pat to subexpressions of the
28nested pseudolist expression xpr and executes body in this context.
29
30==== bind-lambda
31
32<syntax>(bind-lambda pat xpr . xprs)</syntax>
33
34combination of bind and lambda.
35
36==== bind-set!
37
38<syntax>(bind-set! pat xpr)</syntax>
39
40sets the pattern variables of the pattern pat to corresponding
41subexpressions of the nested pseudolist xpr.
42
43==== bind-define
44
45<syntax>(bind-define pat xpr)</syntax>
46
47defines the pattern variables of the pattern pat by setting them to
48corresponding subexpressions of the nested pseudolist xpr.
49
50==== bind-let*
51
52<syntax>(bind-let* ((pat xpr) ...) . body)</syntax>
53
54binds pattern variables of the pattern pat to corresponding
55subexpressions of the nested pseudolist expression xpr ... in sequence
56and executes body in this context.
57
58==== bind-let
59
60<syntax>(bind-let ((pat xpr) ...) . body)</syntax>
61
62binds pattern variables of the pattern pat to corresponding
63subexpressions of the nested pseudolist expression xpr ... in parallel
64and executes body in this context.
65
66==== bindable?
67
68<syntax>(bindable? pat)</syntax>
69
70returns a predicate which checks, if its only list argument matches
71the patterns pat.
72
73====  bind-case
74
75<syntax>(bind-case xpr clause . clauses)</syntax>
76
77where xpr is a nested pseudolist expression and each clause is of the form
78(pat . body), with pat a pattern.
79
80Matches xpr against each pattern pat in sequence, binds the pattern
81variables of the first matching pat to correspondings subexpressions of
82xpr and executes the corresponding body in this context.
83
84==== bind-case-lambda
85
86<syntax>(bind-case-lambda (pat xpr . xprs) ...)</syntax>
87
88combination of bind-case and lambda.
89
90==== bind/cc
91
92<syntax>(bind/cc cont . body)</syntax>
93
94syntactic sugar for call-with-current-continuation. Captures the current
95contiunuation, binds it to cont and evaluates the body in
96this context.
97
98==== define-macro
99
100<syntax>(define-macro (name . args) (renaming (prefix .  prefixed-identifiers) (comparing keyword-predicate body)))</syntax>
101<syntax>(define-macro (name . args) (renaming (prefix .  prefixed-identifiers) body))</syntax>
102<syntax>(define-macro (name . args) (injecting identifiers (comparing keyword-predicates body)))</syntax>
103<syntax>(define-macro (name . args) (injecting identifiers body))</syntax>
104<syntax>(define-macro (name . args) (comparing keyword-predicate body))</syntax>
105<syntax>(define-macro (name . args) body)</syntax>
106         
107where renaming, injecting and comparing are auxiliary keywords,
108prefixed-identifiers is a list, where all of its items share the same prefix,
109identifiers is a list,
110keyword-predicates is either null or of the form (suffix . suffixed-keywords),
111suffixed-keywords is a list, where all of its items share the same suffix.
112
113
114Simplifies implicit-renaming macros by destructuring
115the macro-code automatically.
116The defined macro is either implicit- or explicit-renaming
117depending on the chosen keyword injecting or renaming.
118The macro either provides identifiers bound to itself injected or
119prefixed-identifiers bound to itself with the prefixed stripped and
120renamed.
121Moreover the macro provides keyword-predicates, suffixed-keywords, to
122check if a symbol compares to the keyword-predicate's name with its
123suffix stripped.
124The short-hand versions simply add the missing clauses with empty lists,
125where a missing injecting or renaming clause is interpreted as
126injecting.
127
128==== let-macro
129
130<syntax>(let-macro ((macro-code macro-body) ...) . body)</syntax>
131
132defines macros with macro-code and macro-body ... in parallel and
133exectues body in this context.
134
135==== letrec-macro
136
137<syntax>(letrec-macro ((macro-code macro-body) ...) . body)</syntax>
138
139defines macros with macro-code and macro-body ... recursively and
140exectues body in this context.
141
142==== macro-rules
143
144<syntax>(macro-rules sym ... () (pat0 tpl0) (pat1 tpl1) ...)</syntax>
145<syntax>(macro-rules sym ... (suffix suffixed-keyword ...) (pat0 tpl0) (pat1 tpl1) ...)</syntax>
146
147This macro is inspired by syntax-rules and is used like it (after issuing
148import-for-syntax). The differences to syntax-rules are the following:
149
150First, injected - hence unhygienic - symbols sym ... before the keyword
151list are allowed. So anaphoric macros are possible and clearly
152documented.
153
154Second, if the keyword-list is nonempty, it must be of the form
155
156  (? keyword? ...)
157
158which means that keyword? is a predicate which checks for its own name
159with the suffix ? stripped (other common suffixes are allowed but
160unusual).
161
162Third, the patterns pat0 pat1 ... are nested lambda-lists, i.e. ellipses
163have no special meaning, if used at all.
164
165Third, the templates tpl0 tpl1 ... evaluate usually to quasiquoted
166expressions as is the case in most low-level macros.
167
168=== Requirements
169
170None
171
172=== Examples
173
174<enscript highlight=scheme>
175
176(use list-bindings)
177(import-for-syntax (only list-bindings macro-rules))
178
179(bind a 1 a) ; -> 1
180(bind (a b) '(1 2)  (list a b)) ; -> '(1 2)
181(bind (x y z w) '(1 2 3 4) (list x y z w)) ; -> '(1 2 3 4)
182(bind (x (y (z . u) . v) . w)
183        '(1 (2 (3 4) 5) 6)
184        (list x y z u v w)) ; -> '(1 2 3 (4) (5) (6))
185((bind-lambda (a (b . c) . d) (list a b c d))
186 '(1 (20 30 40) 2 3)) ; -> '(1 20 (30 40) (2 3))
187(bind-let* (((a b) '(1 2)) ((x . y) '(3))) (list a b x y))
188  ; -> '(1 2 3 ())
189(bind-let* (((a b) '(1 2)) ((x . y) (list a))) (list a b x y))
190  ; -> '(1 2 1 ())
191(bind-let (((a b) '(1 2)) ((x . y) '(3 4 4))) (list a b x y))
192  ; -> '(1 2 3 (4 4))
193(bind-case '(1 (2 3))
194        ((x (y z)) (list x y z))
195        ((x (y . z)) (list x y z))
196        ((x y) (list x y))) ; -> '(1 2 3)
197(bind-case '(1 (2 3))
198        ((x (y . z)) (list x y z))
199        ((x y) (list x y))
200        ((x (y z)) (list x y z))) ; -> '(1 2 (3)))
201(bind-case '(1 (2 3))
202        ((x y) (list x y))
203        ((x (y . z)) (list x y z))
204        ((x (y z)) (list x y z))) ; -> '(1 (2 3))
205(bind-case '(1 (2 . 3))
206        ((x y) (list x y))
207        ((x (y . z)) (list x y z))
208        ((x (y z)) (list x y z))) ; -> '(1 (2 . 3))
209((bind-case-lambda
210        ((a (b . c) . d) (list a b c d))
211        ((e . f) (list e f)))
212 '(1 2 3 4 5)) ; -> '(1 (2 3 4 5))
213(letrec (
214        (my-map
215                (lambda (fn lst)
216                        (bind-case lst
217                                (() '())
218                                ((x . xs) (cons (fn x) (map fn xs))))))
219        )
220        (my-map add1 '(1 2 3))) ; -> '(2 3 4)
221((bindable? (a b)) '(1 2)) ; -> #t
222((bindable? (a . b)) '(1)) ; -> #t
223((bindable? (x)) '(name 1)) ;-> #f
224((bindable? (_ x)) '(name 1)) ; -> #t
225((bindable? (_ x)) '(name 1 2)) ;-> #f
226(begin
227  (bind-set! (a (b . c)) '(1 (2)))
228  (list a b c)) ;-> '(1 2 ())
229(begin
230  (bind-define (push top pop)
231    (let ((state '()))
232      (list
233        (lambda (arg) (set! state (cons arg state)))
234        (lambda () (car state))
235        (lambda () (set! state (cdr state))))))
236  (push 3)
237  (push 5)
238  (top)) ; -> 5
239 
240(define-er-macro (efreeze xpr)
241        (renaming (% %lambda)
242                (comparing ()
243                        `(,%lambda () ,xpr))))
244((efreeze 3)) ; -> 3
245(define-macro (ifreeze xpr)
246        `(lambda () ,xpr))
247((ifreeze 5)) ; -> 5
248(define-macro (alambda args xpr . xprs)
249        (injecting (self)
250                `(letrec ((,self (lambda ,args ,xpr ,@xprs)))
251                         ,self)))
252(define ! (alambda (n) (if (zero? n) 1 (* n (self (- n 1))))))
253(! 5) ; -> 120
254(define-macro (foo pair)
255        (comparing (? bar?) `(if ,(bar? (car pair)) ,@(cdr pair) 'unchecked)))
256(foo (bar 'checked)) ; -> 'checked
257(foo (baz 'checked)) ; -> 'unchecked)
258(define-macro (baz pair)
259        (renaming (% %if)
260                (comparing (? bar?)
261                        `(,%if ,(bar? (car pair)) ,@(cdr pair) 'unchecked))))
262(baz (bar 'checked)) ; -> 'checked
263(baz (foo 'checked)) ; -> 'unchecked
264(define-macro (swap! x y)
265  `(let ((tmp ,x)) (set! ,x ,y) (set! ,y tmp)))
266(let ((x 'x) (y 'y)) (swap! x y) (list x y))
267  ; -> '(y x)
268(letrec-macro (((ifreeze xpr) `(lambda () ,xpr))
269                                                         ((efreeze xpr)
270                                                                (renaming (% %lambda)
271                                                                 `(,%lambda () ,xpr))))
272 ((efreeze ((ifreeze 3)))))
273 ; -> 3
274(let-macro (((ifreeze xpr) `(lambda () ,xpr))
275                                                ((efreeze xpr)
276                                                 (renaming (% %lambda)
277                                                        `(,%lambda () ,xpr))))
278  (list ((efreeze 3)) ((ifreeze 5))))
279  ; -> '(3 5)
280
281(define-syntax aif
282        (macro-rules it ()
283                ((_ test consequent . alternative)
284                 (if (null? alternative)
285                        `(let ((,it ,test))
286                                 (if ,it ,consequent))
287                        `(let ((,it ,test))
288                                 (if ,it ,consequent ,(car alternative)))))))
289(define (mist x) (aif (! x) it))
290(mist 5) ; -> 120
291
292(define-syntax if-then-
293        (macro-rules (? then? else?)
294                ((_ test then-pair)
295                 (if (and (pair? then-pair) (then? (car then-pair)))
296                         `(if ,test
297                                        (begin ,@(cdr then-pair)))
298                         `(error 'if-then- "syntax-error")))
299                ((_ test then-pair else-pair)
300                 (if (and (pair? then-pair) (then? (car then-pair))
301                                                        (pair? else-pair) (else? (car else-pair)))
302                         `(if ,test
303                                        (begin ,@(cdr then-pair))
304                                        (begin ,@(cdr else-pair)))
305                         `(error 'if-then- "syntax-error")))))
306(define (quux x)
307        (if-then- (odd? x) (then "odd") (else "even")))
308(quux 3) ; -> "odd"
309(quux 4) ; -> "even"
310
311</enscript>
312
313== Last update
314
315Oct 26, 2013
316
317== Author
318
319[[/users/juergen-lorenz|Juergen Lorenz]]
320
321== License
322
323 Copyright (c) 2011-2013, Juergen Lorenz
324 All rights reserved.
325
326 Redistribution and use in source and binary forms, with or without
327 modification, are permitted provided that the following conditions are
328 met:
329 
330 Redistributions of source code must retain the above copyright
331 notice, this list of conditions and the following disclaimer.
332 
333 Redistributions in binary form must reproduce the above copyright
334 notice, this list of conditions and the following disclaimer in the
335 documentation and/or other materials provided with the distribution.
336 Neither the name of the author nor the names of its contributors may be
337 used to endorse or promote products derived from this software without
338 specific prior written permission.
339   
340 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
341 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
342 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
343 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
344 HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
345 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
346 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
347 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
348 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
349 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
350 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
351
352== Version History
353
354; 1.7 : macro-rules added
355; 1.6 : bind-lambda and bind-case-lambda added
356; 1.5 : bind-set! and bind-define added, code partially rewritten
357; 1.4 : let-macro and letrec-macro added
358; 1.3 : define-macro now incorporates define-ir-macro and define-er-macro, which are no longer exported
359; 1.2 : define-macro added
360; 1.1 : bind-let and bind-let* added
361; 1.0 : initial import
Note: See TracBrowser for help on using the repository browser.