source: project/wiki/eggref/4/bindings @ 29497

Last change on this file since 29497 was 29497, checked in by juergen, 6 years ago

bind-matches? to bind?

File size: 11.0 KB
Line 
1[[tags: egg]]
2[[toc:]]
3
4== bindings
5
6The bindings module is a light-weight alternative to the matchable egg together with some enhancements, in particular the bind macro, which is Common Lisp's destructuring-bind.
7
8Contrary to matchable, there is no attempt to implement ellipses, Scheme's dotted lists must do. Instead of the match macro you should use bind-case. And contrary to matchable, all binding macros can destructure arbitrary nested sequences, i.e. mixtures of lists, pseudo-lists, vectors and strings.
9
10== Documentation
11
12This documentation uses special ellipses, .. and ...., to repeat the
13pattern(s) to the left zero or one and one or many times respectively
14=== Programming interface
15
16==== bindings
17
18Like modules written in the Design by Contract style, this module
19contains its documentation builtin in the form of a dispatcher routine
20with the modules name, bindings, which when called with no argument
21
22<enscript highlight=scheme>(bindings)</enscript>
23
24returns the list of exported symbols, namely
25
26<enscript highlight=scheme>
27(bindings bind bind-case bind-case-lambda bind-case-lambda* bind-define
28 bind-lambda bind-lambda* bind-let bind-let* bind-letrec bind*
29 bind? bind-set! bindrec generic-null-car-cdr! generic-null? generic-car
30 generic-cdr)
31</enscript>
32
33which are all macros, except the generic functions. When calling bindings with one of this symbols, e.g.
34
35<enscript highlight=scheme>(bindings 'bind)</enscript>
36
37the documentation of this symbol in all it's glory is shown, i.e. together
38with admissible forms and a documentation string
39
40<enscript highlight=scheme>
41(bind pat seq (where . fenders) .. xpr . xprs)
42binds pattern variables of pat to subexpressions of seq
43and executes xpr . xprs in this context. Fenders can be used to reject
44an otherwise matching pattern.
45</enscript>
46
47
48====  bind
49
50<syntax>(bind pat seq xpr . xprs)</syntax>
51
52binds pattern variables of pat to subexpressions of seq and executes xpr . xprs in this context
53
54==== bind?
55
56<syntax>(bind? pat (where . fenders) .. ....)</syntax>
57
58returns a predicate which checks, if its only sequence argument matches
59any of the patterns pat ...., accepted by fenders, if given.
60
61====  bind-case
62
63<syntax>(bind-case seq clause ....)</syntax>
64
65where seq is a sequence expression and each clause is of one of two forms
66
67<enscript highlight=scheme>
68(pat (where . fenders) xpr . xprs)
69(pat xpr . xprs)
70</enscript>
71
72Matches seq against a series of patterns and executes the body of the
73first matching pattern satisfying fenders (if given).
74
75==== bind-case-lambda
76
77<syntax>(bind-case-lambda clause ....)</syntax>
78
79where each clause is of one of two forms
80
81<enscript highlight=scheme>
82(pat (where . fenders) xpr . xprs)
83(pat xpr . xprs)
84</enscript>
85
86Combination of bind-case and lambda with one pattern argument
87
88==== bind-case-lambda*
89
90<syntax>(bind-case-lambda* clause ....)</syntax>
91
92where each clause is of one of two forms
93
94<enscript highlight=scheme>
95(pat (where . fenders) xpr . xprs)
96(pat xpr . xprs)
97</enscript>
98
99Combination of bind-case and lambda with multiple pattern arguments
100
101==== bind-lambda
102
103<syntax>(bind-lambda pat (where . fenders) .. xpr . xprs)</syntax>
104
105combination of lambda and bind, one pattern argument
106
107====  bind-lambda*
108
109<syntax>(bind-lambda* pat (where . fenders) .. xpr . xprs)</syntax>
110
111combination of lambda and bind, multiple pattern arguments
112
113====  bind-let
114
115<syntax>(bind-let loop.. ((pat seq) ...) xpr . xprs)</syntax>
116
117like let, named and unnamed, but binds patterns to sequence templates.  In the named case loop is bound to a one-parameter-procedure accessible in the body xpr . xprs
118
119==== bind-let*
120
121<syntax>(bind-let* ((pat seq) ...) xpr . xprs)</syntax>
122
123like let*, but binds patterns to sequence templates
124
125==== bind-letrec
126
127<syntax>(bind-letrec ((pat seq) ...) xpr . xprs)</syntax>
128
129like letrec, but binds patterns to sequence templates
130
131==== bind*
132
133<syntax>(bind* loop pat seq xpr . xprs)</syntax>
134
135bind* is for bind what named let is for let. proc is bound to a one-parameter procedure, which can be used in the body xpr . xprs
136
137==== bindrec
138
139<syntax>(bindrec pat seq xpr . xprs)</syntax>
140
141bind pattern variables of pat to subsequences of seq recursively
142
143==== bind-define
144
145<syntax>(bind-define pat seq)</syntax>
146
147defines pattern variables of pat with values matching subexpressions of seq in one go
148
149==== bind-set!
150
151<syntax>(bind-set! pat seq)</syntax>
152
153sets symbols of pat to corresponding subexpressions of seq
154
155==== bind/cc
156
157<syntax>(bind/cc k xpr . xprs)</syntax>
158
159captures the current continuation as a unary escape procedure, binds it
160to k and executes xpr . xprs in this context, possibly calling k.
161
162==== generic-null-car-cdr!
163
164<procedure>(generic-null-car-cdr! type-pred null-proc car-proc cdr-proc)</procedure>
165
166updates the table of generic functions.
167
168As implemented, the binding macros can handle arbitrary nested combinations of
169(pseudo-)lists, vectors,strings and records. But updating the table additional
170sequence types can be handled without touching the macros' code.
171
172=== Requirements
173
174None
175
176=== Usage
177
178<enscript highlight=scheme>(use bindings)</enscript>
179
180=== Examples
181
182<enscript highlight=scheme>
183
184(use bindings tuples)
185
186(let ((stack #f) (push! #f) (pop! #f))
187  (bind-set! (stack (push! pop!))
188    (list
189      '()
190      (vector
191        (lambda (xpr) (set! stack (cons xpr stack)))
192        (lambda () (set! stack (cdr stack))))))
193  (push! 1)
194  (push! 0)
195  stack)
196; -> '(0 1)
197
198(begin
199  (bind-define (top push! pop!)
200    (let ((lst '()))
201      (vector
202        (lambda () (car lst))
203        (lambda (xpr) (set! lst (cons xpr lst)))
204        (lambda () (set! lst (cdr lst))))))
205  (push! 0)
206  (push! 1)
207  (pop!)
208  (top))
209; -> 0
210
211(bind a 1 a) ; -> 1
212
213(bind (x y z w) '(1 2 3 4) (list x y z w) ; -> '(1 2 3 4)
214
215(bind (x . y) '#(1 2 3 4) (list x y)) ; -> '(1 #(2 3 4))
216
217(bind (x (y (z u . v)) w) '(1 #(2 "foo") 4)
218  (list x y z u v w))
219; -> '(1 2 #\f #\o "o" 4)
220
221(bind (x (y (z . u)) v . w) (vector 1 (list 2 (cons 3 4)) 5 6)
222  (list x y z u v w))
223; -> '(1 2 3 4 5 #(6))
224
225((bind-lambda (a (b . C) . d)
226   (list a b C d))
227 '(1 #(20 30 40) 2 3))
228; -> '(1 20 #(30 40) (2 3))
229
230((bind-lambda* ((a (b . C) . d) (e . f))
231   (list a b C d e f))
232 '(1 #(20 30 40) 2 3) '#(4 5 6))
233; -> '(1 20 #(30 40) (2 3) 4 #(5 6))
234
235(bind* loop (x (a . b) y) '(5 #(1) 0)
236  (if (zero? x)
237    (list x a b y)
238    (loop (list (- x 1) (cons a (cons a b)) (+ y 1)))))
239; -> '(0 1 (1 1 1 1 1 . #()) 5)
240
241(bind* loop (x y) '(5 0)
242  (if (zero? x)
243    (vector x y)
244    (loop (vector (- x 1) (+ y 1)))))
245; -> '#(0 5)
246
247(bind-let (((x y (z . w)) '(1 2 #(3 4 5))))
248  (list x y z w))
249; -> '(1 2 3 #(4 5))
250
251(bind-let (
252  (((x y) z) '(#(1 2) 3))
253  (u (+ 2 2))
254  ((v w) '#(5 6))
255  )
256  (list x y z u v w))
257; -> '(1 2 3 4 5 6)
258
259(bind-let loop (((a b) '(5 0)))
260  (if (zero? a)
261    (list a b)
262    (loop (list (list (- a 1) (+ b 1))))))
263; -> '(0 5)
264
265(bind-let loop (
266  ((x . y) '(1 2 3))
267  ((z) '#(10))
268  )
269  (if (zero? z)
270    (list x y z)
271    (loop (list (cons (+ x 1) (map add1 y)) (list (- z 1))))))
272; -> '(11 (12 13) 0)
273
274(bind-let* (
275  (((x y) z) '(#(1 2) 3))
276  (u (+ 1 2 x))
277  ((v w) (list (+ z 2) 6))
278  )
279  (list x y z u v w))
280; -> '(1 2 3 4 5 6)
281
282(bindrec ((o?) e?)
283  (vector (list (lambda (m) (if (zero? m) #f (e? (- m 1)))))
284          (lambda (n) (if (zero? n) #t (o? (- n 1)))))
285  (list (o? 95) (e? 95)))
286; -> '(#t #f)
287
288(bind-letrec (
289  ((o? (e?))
290   (list (lambda (m) (if (zero? m) #f (e? (- m 1))))
291         (vector (lambda (n) (if (zero? n) #t (o? (- n 1)))))))
292  )
293  (list (o? 95) (e? 95)))
294; -> '(#t #f)
295
296(let ((two '(1 2)))
297  (bind-matches? two ()))
298; -> #f
299
300((bind? ()) '()) ; -> #t
301
302((bind? (a (b C) . d)) '(1 (2 3) . 4)) ; -> #t
303
304((bind? (a (b C) . d)) '(1 #(2 3) 4 5)) ; -> #t
305
306((bind? (a (b . C) . d)) '(1 (2 3) 4)) ; -> #t
307
308((bind? (a (b . C) . d)) '#(1 2 3 4 5)) ; -> #f
309
310((bind? (a (b C) d)) '(1 (2 3) 4 5)) ; -> #f
311
312((bind? (a b) (where (even? a)) (a b)) '#(1 2)) ; -> #t
313
314(bind-case '#(1 2)
315  (() '())
316  ((a) (list a))
317  ((a b) (list a b))
318  ((a b C) (list a b C)))
319; -> '(1 2))
320
321(letrec (
322  (my-map
323    (lambda (fn lst)
324      (bind-case lst
325        (() '())
326        ((x . xs) (cons (fn x) (map fn xs))))))
327  )
328  (my-map add1 '(1 2 3)))
329; -> '(2 3 4)
330
331((bind-case-lambda
332         ((a (b . C) . d) (list a b C d))
333         ((e . f) (where (zero? e)) e)
334         ((e . f) (list e f)))
335 '(1 2 3 4 5))
336; -> '(1 (2 3 4 5)))
337
338((bind-case-lambda
339         ((e . f) (where (zero? e)) f)
340         ((e . f) (list e f)))
341 '#(0 2 3 4 5))
342;-> '#(2 3 4 5))
343
344((bind-case-lambda
345   ((a (b . C) . d) (list a b C d))
346   ((e . f) (list e f)))
347 '(1 #(2 3 4) 5 6))
348; -> '(1 2 #(3 4) (5 6))
349
350((bind-case-lambda*
351   (((a b C . d) (e . f))
352    (list a b C d e f)))
353 '(1 2 3) '#(4 5 6))
354; -> '(1 2 3 () 4 #(5 6))
355
356((bind-case-lambda*
357   (((a (b . C) . d) (e . f))
358    (list a b C d e f)))
359 '(1 #(20 30 40) 2 3) '(4 5 6))
360; -> '(1 20 #(30 40) (2 3) 4 (5 6))
361
362(define-record point x y)
363(bind (x y) (make-point 1 2) (list x y)) ;-> '(1 2)
364(bind (x (y z)) (vector 1 (make-point 2 3)) (list x y z))
365      ;-> '(1 2 3)
366(bind (x . y) (make-point 1 2) (list x y)) ;-> '(1 #(2))
367
368;;adding new types to generics
369(generic-null-car-cdr! tuple? tuple-empty? tuple-left tuple-butleft)
370(bind (x y z) (tuple 1 2 3) (list x y z)) ;-> '(1 2 3)
371(bind (x (y z)) (vector 0 (tuple 1 2)) (list x y z)) ;-> '(0 1 2)
372
373</enscript>
374
375== Last update
376
377Jun 28, 2013
378
379== Author
380
381[[/users/juergen-lorenz|Juergen Lorenz]]
382
383== License
384
385 Copyright (c) 2011-2013, Juergen Lorenz
386 All rights reserved.
387
388 Redistribution and use in source and binary forms, with or without
389 modification, are permitted provided that the following conditions are
390 met:
391 
392 Redistributions of source code must retain the above copyright
393 notice, this list of conditions and the following disclaimer.
394 
395 Redistributions in binary form must reproduce the above copyright
396 notice, this list of conditions and the following disclaimer in the
397 documentation and/or other materials provided with the distribution.
398 Neither the name of the author nor the names of its contributors may be
399 used to endorse or promote products derived from this software without
400 specific prior written permission.
401   
402 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
403 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
404 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
405 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
406 HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
407 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
408 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
409 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
410 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
411 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
412 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
413
414== Version History
415
416; 2.1 : generics (and hence bind and friends) now accept records, bind/cc added
417
418; 2.0 : bind-matches? and bind-loop changed to bind? and bind*, where clauses and generic functions added, syms->vars removed
419
420; 1.0 : all binding macros can now destructure arbitrary nested sequences, i.e mixtures of lists, pseudo-lists, vectors and strings; dependency on contracts removed.
421
422; 0.1 : initial import
Note: See TracBrowser for help on using the repository browser.