source: project/wiki/eggref/4/ck-macros @ 33169

Last change on this file since 33169 was 33169, checked in by jacius, 3 years ago

ck-macros: Final docs for version 0.1.0.

File size: 33.6 KB
Line 
1== ck-macros
2
3Composable Scheme macros based on the CK abstract machine.
4
5This egg is based on the CK-macro system described in
6"[[http://okmij.org/ftp/Scheme/macros.html#ck-macros|Applicative syntax-rules: macros that compose better]]"
7by Oleg Kiselyov.
8This egg provides the core {{ck}} macro,
9plus many useful (and some not-so-useful) predefined CK-macros.
10
11If you create a useful or interesting general-purpose CK-macro,
12or an improvement to an existing CK-macro,
13please contact the maintainer (John) so your contribution can be added to the egg.
14All source code (including contributions) is public domain.
15
16; Project / Source Code Repository: [[https://gitlab.com/jcroisant/ck-macros]]
17; Maintainer: [[/users/john-croisant|John Croisant]]
18; Based on work by: Oleg Kiselyov
19; License: Public Domain
20
21
22'''Table of Contents'''
23[[toc:]]
24
25
26=== Version History
27
28; 0.1.0 (2016-02-06) : Initial release. Includes version 1.1 (April 2011) of the core {{ck}} macro. Includes many CK-macros.
29
30For more information about what changed in each version,
31see the [[https://gitlab.com/jcroisant/ck-macros/blob/master/CHANGELOG.md|CHANGELOG]].
32
33
34=== What are CK-macros?
35
36CK-macros are Scheme macros written to be compatible with with the core {{ck}} macro.
37
38The core {{ck}} macro is a {{syntax-rules}} macro which implements the CK abstract machine.
39The CK abstract machine is a theoretical model of computation,
40described in the paper "Control Operators, the SECD-Machine, and the Lambda-Calculus"
41by Matthias Felleisen and Daniel P. Friedman.
42But, you don't need to read or understand the paper in order to create or use CK-macros!
43
44Basically, a CK-macro leverages the core {{ck}} macro
45to recursively expand the CK-macros's arguments first,
46before the CK-macro itself is expanded.
47This gives you more control over the macro expansion process,
48allowing you to easily combine simple reusable macros to form more complex macros.
49
50This is very similar to the way Scheme allows you to easily combine simple resuable functions
51({{map}}, {{fold}}, {{cons}}, etc.) to create more complex functions.
52In fact, many useful Scheme functions can be translated to CK-macros,
53allowing you to portably achieve the same effect at macro-expansion time.
54You can even implement "higher-ordered macros" which take a macro as an argument.
55See {{c-map}} and {{c-fold}} for examples of higher-ordered macros.
56
57CK-macros are not as flexibile or powerful as
58CHICKEN's [[/manual/Macros|explicit and implicit renaming macros]],
59but CK-macros are much more portable.
60The [[#ck|core {{ck}} macro]] and all the macros in the [[#portable-ck-macros|Portable CK-Macros]] section
61are implemented using only standard R5RS features,
62such as {{syntax-rules}} and {{let-syntax}}.
63This means they will work on any implementation of R5RS or later.
64
65
66=== How to write CK-macros
67
68Here is a basic template for CK-macros:
69
70<enscript highlight="scheme">
71(define-syntax c-foo
72  (syntax-rules (quote)
73    ((c-foo s 'input1 'input2 ...)
74     (ck s output))))
75</enscript>
76
77A CK-macro is just a normal macro that expands to a call to the core {{ck}} macro.
78To be portable, CK-macros are usually written using {{syntax-rules}}.
79But, you can write CK-macros using other macro systems,
80such as CHICKEN's [[/manual/Macros|explicit and implicit renaming macros]],
81as long your macro eventually expands into a call to the core {{ck}} macro.
82
83By convention, the names of CK-macros usually start with "c-",
84to distinguish them from non-CK macros or procedures with similar names.
85But, this naming convention is not required.
86
87CK-macros treat quoting specially, so you should have {{quote}} in the list of literal identifiers (the first argument to {{syntax-rules}}).
88You can also have other literal identifiers if needed.
89
90Every CK-macro's first argument must be the stack, usually called {{s}}.
91The stack is used internally by the core {{ck}} macro while recursively expanding macro arguments.
92Your CK-macro should not touch the stack, only pass it through to the core {{ck}} macro.
93
94Each {{'input}} is an argument passed to your macro.
95Your macro can have any number of input arguments, and they can be named whatever you want.
96They can also be lists or patterns, allowing you to destructure the arguments,
97as is often done with {{syntax-rules}} macros.
98
99The core {{ck}} macro expands the input arguments ahead of time,
100so the arguments will always be quoted values by the time your macro is expanded.
101Usually CK-macros are defined with their input arguments quoted (as above),
102so that you can easily destructure the input to use in your macro.
103You may recall that {{'a}} is translated by the reader to {{(quote a)}}.
104So, the above example is exactly the same as:
105
106<enscript highlight="scheme">
107(define-syntax c-foo
108  (syntax-rules (quote)
109    ((c-foo s (quote input1) (quote input2) ...)
110     (ck s output))))
111</enscript>
112
113When written in this way, it is easier to see that {{input1}} and {{input2}}
114are merely placeholders in the {{syntax-rules}} pattern.
115(This is also why you must tell {{syntax-rules}} that {{quote}} is a literal identifier.
116Otherwise, {{syntax-rules}} would treat {{quote}} as a placeholder, too.)
117
118Your macro should transform the {{input}}s in some way to produce the {{output}},
119which is passed to the core {{ck}} macro.
120The {{output}} must be either:
121
122* A quoted value, such as {{'a}}, {{'(+ 1 2)}}, {{'"foo"}}, {{'42}}, or {{'#t}}.
123* Or, an unquoted call to a CK-macro '''without the s argument''', such as {{(c-cons '+ '(1 2))}}.
124  Nested calls are allowed, such as {{(c-cons '+ (c-list '1 '2))}}.
125
126Quoting is how the core {{ck}} macro knows the difference between a value and a CK-macro call.
127Therefore, '''all values must be quoted''',
128even values which normally do not need to be quoted in Scheme code,
129such as strings, numbers, and booleans.
130
131Eventually, your CK-macro must expand into a call to the core {{ck}} macro
132with a quoted value.
133We say that the macro "yields" this quoted value.
134The quoted value is either used as an argument to another CK-macro,
135or if your CK-macro is the outer-most CK-macro call,
136then the core {{ck}} macro expands into the '''unquoted value'''.
137
138So, if your CK-macro yields the quoted value {{'(+ 1 2)}},
139and it is the outer-most CK-macro (not an argument to another CK-macro),
140the core {{ck}} macro will expand to the unquoted expression {{(+ 1 2)}},
141which would later be evaluated to the number 3.
142(If you want to yield a quoted form as the final result,
143use {{c-quote}} as the outer-most CK-macro.)
144
145See [[http://okmij.org/ftp/Scheme/macros.html#ck-macros|the original article]]
146or [[https://gitlab.com/jcroisant/ck-macros/blob/master/ck-portable.scm|the source code]]
147for many examples of CK-macros.
148
149
150=== Combining CK and non-CK macros
151
152The arguments to a CK-macro must either be a quoted value or a call to a CK-macro
153(i.e. a macro that expands to a call to the core {{ck}} macro).
154Therefore, most non-CK macros and special forms cannot be used as arguments to a CK-macro.
155
156Some non-CK macros can be used in a way that expands into a user-provided expression.
157It is therefore possible for these non-CK macros to be used as arguments CK-macros,
158as long as they eventually expand into a call to the core {{ck}} macro.
159
160It is possible to write a non-CK macro which invokes a CK-macro via the core {{ck}} macro.
161For example, if you are writing a macro for other people to use,
162you can create a convenience wrapper macro, like so:
163
164<enscript highlight="scheme">
165;;; Convenience wrapper around c-foo.
166(define-syntax foo
167  (syntax-rules ()
168    ((foo arg1 arg2 arg3)
169     (ck () (c-foo 'arg1 'arg2 'arg3)))))
170</enscript>
171
172Also, it is possible for a CK-macro to expand into a call to a non-CK macro as its final result,
173or as part of the body of its final result.
174For example:
175
176<enscript highlight="scheme">
177(ck () (c-list 'when (c-list '< '1 '2) (c-list 'print '"Yay!")))
178;;; Expands to the expression (when (< 1 2) (print "Yay!")).
179</enscript>
180
181
182=== ck
183
184<syntax>(ck s 'v)</syntax>
185<syntax>(ck s (op ...))</syntax>
186
187This is the core {{ck}} macro, which implements the CK abstract machine.
188This macro's public interface has two shapes:
189one with a quoted value, and one with a CK-macro call.
190
191; s : The stack, used internally by this macro. When initially invoking this macro, {{s}} should be the empty list, e.g. {{(ck () (c-cons '+ '(1 2)))}}.
192; 'v : A quoted value. Can be a quoted list, symbol, or other literal value. The quote is necessary, even for literal values like strings, numbers, and booleans.
193; (op ...) : A CK-macro call '''without the s argument''', such as {{(c-cons '+ '(1 2))}}. Nested calls are allowed, such as {{(c-cons '+ (c-list '1 '2))}}.
194
195
196=== Portable CK-Macros
197
198The CK-macros in this section are defined using only standard R5RS features,
199such as {{syntax-rules}} and {{let-syntax}}.
200So, these CK-macros will work on any implementation of R5RS or later.
201
202
203==== General
204
205<syntax>(c-quote X)  →  'X</syntax>
206
207Adds an extra level of quotation to the argument.
208This is useful for macros that should expand to a quoted value.
209
210<enscript highlight="scheme">
211;; Without c-quote
212(ck () (c-cons '+ '(1 2)))
213;; Expands to (+ 1 2), which evaluates to the number 3.
214
215;; With c-quote
216(ck () (c-quote (c-cons '+ '(1 2))))
217;; Expands to '(+ 1 2), a quoted list.
218</enscript>
219
220
221<syntax>(c-eval '(OP ...))  →  result</syntax>
222
223Takes a quoted operation and unquotes it,
224allowing the CK machine to expand it.
225Analogous to {{eval}}.
226
227<enscript highlight="scheme">
228(ck () (c-quote (c-eval '(c-cons 'a 'b))))
229;; ==> '(a . b)
230</enscript>
231
232
233<syntax>(c-call '(OP ...) X ...)  →  result</syntax>
234
235Like {{c-eval}}, but adds the given arguments on to the end of the operation.
236Analogous to a lambda call in normal Scheme code.
237
238<enscript highlight="scheme">
239(ck () (c-quote (c-call '(c-cons 'a) 'b)))
240;; ==> '(a . b)
241</enscript>
242
243
244<syntax>(c-apply '(OP ...) X ... '(Y ...))  →  result</syntax>
245
246Like {{c-call}}, but the last argument is a list of more arguments.
247Analogous to {{apply}}.
248
249<enscript highlight="scheme">
250(ck () (c-quote (c-apply '(c-list) 'a 'b '(c d))))
251;; ==> '(a b c d)
252</enscript>
253
254
255<syntax>(c-identity X)  →  X</syntax>
256
257Simply yields the value as given.
258Sometimes useful for higher-order macros like {{c-filter}}.
259
260<enscript highlight="scheme">
261(ck () (c-quote (c-identity 'a)))
262;; ==> 'a
263</enscript>
264
265
266==== Boolean Logic
267
268<syntax>(c-not X)  →  '#t or '#f</syntax>
269
270Yields {{'#t}} if the argument is {{'#f}}, otherwise yields {{'#f}}.
271Analogous to {{not}}.
272
273
274<syntax>(c-if TEST PASS FAIL)  →  PASS or FAIL</syntax>
275
276Conditional branching.
277If {{TEST}} is {{'#f}}, this yields {{FAIL}}.
278Otherwise it yields {{PASS}}.
279
280Due to the way the CK machine works, both branches will be expanded,
281then the unneeded branch will be discarded.
282If you only want the needed branch to be expanded
283(e.g. because the branches are complex and slow to expand,
284or because it would be an error to expand the unneeded branch),
285use {{c-if*}} instead.
286
287Analogous to
288{{(lambda (test pass fail) (if test pass fail))}}.
289
290<enscript highlight="scheme">
291(ck () (c-quote (c-if (c-pair? '(x))
292                      'pair
293                      'not-pair)))
294;; ==> 'pair
295
296(ck () (c-quote (c-if (c-pair? 'x)
297                      'pair
298                      'not-pair)))
299;; ==> 'not-pair
300</enscript>
301
302
303<syntax>(c-if* TEST 'PASS 'FAIL)  →  PASS or FAIL</syntax>
304
305Similar to {{c-if}}, except that the branches must have an extra level of quoting,
306and only one branch will be expanded.
307This is more similar to how {{if}} behaves, but it is a bit awkward to use.
308
309Analogous to
310{{(lambda (test pass fail) (if test (eval pass) (eval fail)))}}
311
312<enscript highlight="scheme">
313(ck () (c-quote (c-if (c-pair? '(x))
314                      '(c-car '(x))
315                      ''not-pair))
316;; ==> 'x
317
318(ck () (c-quote (c-if (c-pair? 'x)
319                      '(c-car 'x)
320                      ''not-pair))
321;; ==> 'not-pair
322</enscript>
323
324
325<syntax>(c-or X ...)  →  item or '#f</syntax>
326
327Yields the first argument that is not {{'#f}}.
328Yields {{'#f}} if all of the arguments are {{'#f}},
329or if there are no arguments.
330
331Roughly analogous to {{or}}, except all arguments are expanded.
332If you only want to expand the arguments that are needed, use {{c-or*}} instead.
333
334
335<syntax>(c-or* 'X ...)  →  item or '#f</syntax>
336
337Similar to {{c-or}}, except that all the arguments must have an extra level of quoting,
338and the arguments will be expanded one at a time until a non-{{'#f}} value is found.
339This is more similar to how {{or}} behaves, but it is a bit awkward to use.
340
341
342<syntax>(c-and X ...)  →  item or '#f</syntax>
343
344If all arguments are not {{'#f}}, yields the last argument.
345If any of the arguments is {{'#f}}, yields {{'#f}}.
346If there are no arguments, yields {{'#t}}.
347
348Roughly analogous to {{and}}, except all arguments are expanded.
349If you only want to expand the arguments that are needed, use {{c-and*}} instead.
350
351
352<syntax>(c-and* X ...)  →  item or '#f</syntax>
353
354Similar to {{c-and}}, except that all the arguments must have an extra level of quoting,
355and the arguments will be expanded one at a time until a {{'#f}} value is found.
356This is more similar to how {{and}} behaves, but it is a bit awkward to use.
357
358
359<syntax>(c-null? X)  →  '#t or '#f</syntax>
360
361Yields {{'#t}} if {{X}} is the empty list, {{'()}}.
362Otherwise yields {{'#f}}.
363Analogous to {{null?}}.
364
365
366<syntax>(c-pair? X)  →  '#t or '#f</syntax>
367
368Yields {{'#t}} if {{X}} is a dotted pair or a non-empty list.
369Otherwise yields {{'#f}}.
370Analogous to {{pair?}}.
371
372
373<syntax>(c-not-pair? X)  →  '#t or '#f</syntax>
374
375Opposite of {{c-pair?}}.
376Analogous to {{not-pair?}} from SRFI-1.
377
378
379<syntax>(c-vector? X)  →  '#t or '#f</syntax>
380
381Yields {{'#t}} if {{X}} is a vector.
382Otherwise yields {{'#f}}.
383Analogous to {{vector?}}.
384
385<enscript highlight="scheme">
386(ck () (c-quote (c-vector? '#(a))))
387;; ==> '#t
388</enscript>
389
390
391<syntax>(c-boolean? X)  →  '#t or '#f</syntax>
392
393Yields {{'#t}} if {{X}} is either {{'#t}} or {{'#f}}.
394Otherwise yields {{'#f}}.
395Analogous to {{boolean?}}.
396
397
398<syntax>(c-sym-eq? X Y)  →  '#t or '#f</syntax>
399
400Yields {{'#t}} if {{X}} and {{Y}} are the same symbol, otherwise yields {{'#f}}.
401{{X}} should be a symbol.
402{{Y}} can be any value.
403Some Scheme implementations allow {{X}} to be other types,
404but this macro is only portable if {{X}} is a symbol.
405
406Roughly analogous to {{eq?}},
407except it only works (portably) with symbols.
408Based on {{symbol-eq?}} from the original implementation.
409
410
411<syntax>(c-sym-equal? X Y)  →  '#t or '#f</syntax>
412
413Similar to {{c-sym-eq?}}, except it recursively compares
414pairs, lists, and vectors.
415
416Roughly analogous to {{equal?}},
417except it only works (portably) with symbols, pairs, lists, vectors,
418and nested combinations of those things.
419
420
421==== List Processing
422
423<syntax>(c-cons X Y)  →  pair</syntax>
424
425Yields a pair with the two given arguments.
426Analogous to {{cons}}.
427
428<enscript highlight="scheme">
429(ck () (c-quote (c-cons '"a" '1)))
430;; Expands to '("a" . 1).
431
432(ck () (c-quote (c-cons '+ '(1 2))))
433;; Expands to '(+ 1 2).
434
435(ck () (c-quote (c-cons '+ (c-cons '1 (c-cons '2 '())))))
436;; Also expands to '(+ 1 2).
437</enscript>
438
439
440<syntax>(c-list X ...)  →  list</syntax>
441
442Yields a list containing the given items.
443Analogous to {{list}}.
444
445<enscript highlight="scheme">
446(ck () (c-quote (c-list)))
447;; ==> '()
448(ck () (c-quote (c-list 'a 'b 'c)))
449;; ==> '(a b c)
450</enscript>
451
452
453<syntax>(c-car P)  →  item</syntax>
454
455Yields the head of the given pair.
456Analogous to {{car}}.
457
458<enscript highlight="scheme">
459(ck () (c-quote (c-car '(a . b))))
460;; ==> 'a
461
462(ck () (c-quote (c-car '(a b))))
463;; ==> 'a
464</enscript>
465
466
467<syntax>(c-cdr P)  →  tail</syntax>
468
469Yields the tail of the given pair.
470Analogous to {{cdr}}.
471
472<enscript highlight="scheme">
473(ck () (c-quote (c-cdr '(a . b))))
474;; ==> 'b
475
476(ck () (c-quote (c-cdr '(a b))))
477;; ==> '(b)
478</enscript>
479
480
481<syntax>(c-first   L)  →  item</syntax>
482<syntax>(c-second  L)  →  item</syntax>
483<syntax>(c-third   L)  →  item</syntax>
484<syntax>(c-fourth  L)  →  item</syntax>
485<syntax>(c-fifth   L)  →  item</syntax>
486<syntax>(c-sixth   L)  →  item</syntax>
487<syntax>(c-seventh L)  →  item</syntax>
488<syntax>(c-eighth  L)  →  item</syntax>
489<syntax>(c-ninth   L)  →  item</syntax>
490<syntax>(c-tenth   L)  →  item</syntax>
491
492Yields the Nth item of the given list.
493Fails if the list is too short.
494
495Analogous to {{first}} ... {{tenth}} from SRFI-1.
496
497<enscript highlight="scheme">
498(ck () (c-quote (c-first  '(a b c d e f g h i j k))))  ; ==> 'a
499(ck () (c-quote (c-second '(a b c d e f g h i j k))))  ; ==> 'b
500(ck () (c-quote (c-third  '(a b c d e f g h i j k))))  ; ==> 'c
501;;; ...
502(ck () (c-quote (c-tenth  '(a b c d e f g h i j k))))  ; ==> 'j
503</enscript>
504
505
506<syntax>(c-last L)  →  item</syntax>
507
508Yields the last value of the given list.
509Fails if the list is empty or is not a proper list.
510
511Analogous to {{last}} from SRFI-1.
512
513<enscript highlight="scheme">
514(ck () (c-quote (c-last '(a b c))))    ; ==> 'c
515(ck () (c-quote (c-last '(a b . c))))  ; ==> ERROR!
516</enscript>
517
518
519<syntax>(c-last-pair L)  →  pair</syntax>
520
521Yields the last pair of the given list.
522Fails if the list is empty.
523
524Analogous to {{last-pair}} from SRFI-1.
525
526<enscript highlight="scheme">
527(ck () (c-quote (c-last-pair '(a b c))))    ; ==> '(c)
528(ck () (c-quote (c-last-pair '(a b . c))))  ; ==> '(b . c)
529</enscript>
530
531
532<syntax>(c-drop1 L)  →  list</syntax>
533<syntax>(c-drop2 L)  →  list</syntax>
534<syntax>(c-drop3 L)  →  list</syntax>
535<syntax>(c-drop4 L)  →  list</syntax>
536<syntax>(c-drop5 L)  →  list</syntax>
537
538Drops a predefined number of items from the front of the given list.
539Fails if the list is too short.
540See also {{c-udrop}}.
541
542Analogous to {{(drop L N)}} from SRFI-1.
543
544<enscript highlight="scheme">
545(ck () (c-quote (c-drop1 '(a b c d e f g))))  ; ==> '(b c d e f g)
546(ck () (c-quote (c-drop2 '(a b c d e f g))))  ; ==> '(c d e f g)
547(ck () (c-quote (c-drop3 '(a b c d e f g))))  ; ==> '(d e f g)
548(ck () (c-quote (c-drop4 '(a b c d e f g))))  ; ==> '(e f g)
549(ck () (c-quote (c-drop5 '(a b c d e f g))))  ; ==> '(f g)
550</enscript>
551
552
553<syntax>(c-take1 L)  →  list</syntax>
554<syntax>(c-take2 L)  →  list</syntax>
555<syntax>(c-take3 L)  →  list</syntax>
556<syntax>(c-take4 L)  →  list</syntax>
557<syntax>(c-take5 L)  →  list</syntax>
558
559Yields a list containing a predefined number of items from the front of the given list.
560Fails if the list is too short.
561See also {{c-utake}}.
562
563Analogous to {{(take L N)}} from SRFI-1.
564
565<enscript highlight="scheme">
566(ck () (c-quote (c-take1 '(a b c d e f g))))  ; ==> '(a)
567(ck () (c-quote (c-take2 '(a b c d e f g))))  ; ==> '(a b)
568(ck () (c-quote (c-take3 '(a b c d e f g))))  ; ==> '(a b c)
569(ck () (c-quote (c-take4 '(a b c d e f g))))  ; ==> '(a b c d)
570(ck () (c-quote (c-take5 '(a b c d e f g))))  ; ==> '(a b c d e)
571</enscript>
572
573
574<syntax>(c-reverse L)  →  list</syntax>
575
576Yields the given list in reverse order.
577Fails if the list is not a proper list.
578Analogous to {{reverse}}.
579
580<enscript highlight="scheme">
581(ck () (c-quote (c-reverse '(a b c))))
582;; ==> '(c b a)
583</enscript>
584
585
586<syntax>(c-suffix L X ...)  →  list</syntax>
587
588Yields the given list with the extra arguments added to the end.
589
590<enscript highlight="scheme">
591(ck () (c-quote (c-suffix '(a) 'b 'c)))
592;; ==> '(a b c)
593</enscript>
594
595
596<syntax>(c-append L ...)  →  list</syntax>
597
598Appends the given lists.
599Analogous to {{append}}.
600
601<enscript highlight="scheme">
602(ck () (c-quote (c-append)))
603;; ==> '()
604
605(ck () (c-quote (c-append '(+) (c-append '(1) '(2)))))
606;; ==> '(+ 1 2)
607
608(ck () (c-quote (c-append '(define foo) '((+ 1 2)))))
609;; ==> '(define foo (+ 1 2 3))
610</enscript>
611
612
613<syntax>(c-append-map '(OP ...) L)  →  list</syntax>
614
615Yields a list by calling the quoted operation on each item in the list,
616then appending the results.
617The operation must be a CK-macro that yields a list.
618The operation may have leading arguments.
619
620Analogous to {{append-map}} from SFRI-1, but only accepts one list.
621This was named {{c-concatMap}} in the original implementation.
622
623<enscript highlight="scheme">
624(ck () (c-quote (c-append-map '(c-list 'a 'b) '(1 2))))
625;; ==> '(a b 1 a b 2)
626</enscript>
627
628
629<syntax>(c-map '(OP ...) L)  →  list</syntax>
630
631Yields a list by calling the quoted operation on each item in the given list.
632The operation may have leading arguments.
633Analogous to {{map}}, but only accepts one list.
634
635<enscript highlight="scheme">
636(ck () (c-quote (c-map '(c-cons 'a) '(1 2))))
637;; ==> '((a . 1) (a . 2))
638</enscript>
639
640
641<syntax>(c-fold '(OP ...) INIT L)  →  result</syntax>
642
643Yield a value by repeatedly calling the quoted operation
644with each item from the list plus the previous result.
645
646If the list is empty, yields {{INIT}}.
647Otherwise, the operation is first called with two arguments:
648the first item of the list, and INIT.
649Then, the operation is repeatedly called with the next item of the list and the previous result,
650until it reaches the end of the list.
651Yields the final result.
652
653Analogous to {{fold}} from SRFI-1, but only accepts one list.
654
655<enscript highlight="scheme">
656(ck () (c-quote (c-fold '(c-cons) '(x) '())))
657;; ==> '(x)
658(ck () (c-quote (c-fold '(c-cons) '(x) '(a b c d e f))))
659;; ==> '(f e d c b a x)
660</enscript>
661
662
663<syntax>(c-filter '(OP ...) L)  →  list</syntax>
664
665Yields a list by calling the quoted operation on each item in the given list,
666and discarding any item for which the test yields {{'#f}}.
667Analogous to {{filter}} from SRFI-1.
668
669<enscript highlight="scheme">
670(ck () (c-quote (c-filter '(c-pair?)
671                          '(a (b . c) 1 (d e) #t))))
672;; ==> '((b . c) (d e))
673</enscript>
674
675
676<syntax>(c-remove '(OP ...) L)  →  list</syntax>
677
678Opposite of {{c-filter}}.
679Discards items that pass the test, keeps items that fail the test.
680Analogous to {{remove}} from SRFI-1.
681
682<enscript highlight="scheme">
683(ck () (c-quote (c-remove '(c-pair?)
684                          '(a (b . c) 1 (d e) #t))))
685;; ==> '(a 1 #t)
686</enscript>
687
688
689<syntax>(c-find '(OP ...) L)  →  item or '#f</syntax>
690
691Searches the list for the first item that passes the predicate operation
692(i.e. the predicate yields a non-{{'#f}} value),
693then yields that item.
694Yields {{'#f}} if no item passes the predicate.
695
696Analogous to {{find}} from SRFI-1.
697
698<enscript highlight="scheme">
699(ck () (c-quote (c-find '(c-pair?)
700                        '(a (b . c) 1 (d e) #t))))
701;; ==> '(b . c)
702</enscript>
703
704
705<syntax>(c-find-tail '(OP ...) L)  →  pair or '#f</syntax>
706
707Searches the list for the first item that passes the predicate operation
708(i.e. the predicate yields a non-{{'#f}} value),
709then yields the tail of the list starting with that item.
710Yields {{'#f}} if no item passes the predicate.
711
712Analogous to {{find-tail}} from SRFI-1.
713
714<enscript highlight="scheme">
715(ck () (c-quote (c-find-tail '(c-pair?)
716                             '(a (b . c) 1 (d e) #t))))
717;; ==> '((b . c) 1 (d e) #t)
718</enscript>
719
720
721<syntax>(c-member X L)  →  '#t or '#f</syntax>
722<syntax>(c-member X L '(OP ...))  →  '#t or '#f</syntax>
723
724Searches the list for the first occurance of {{X}},
725then yields the tail of the list starting with that item.
726Yields {{'#f}} if the list does not contain {{X}}.
727
728Uses {{'(OP ...)}} for comparison,
729or {{'(c-sym-equal?)}} if the operation is omitted.
730So by default, {{X}} must be a symbol, list, pair, vector,
731or nested combination of those things.
732
733Same as {{(c-find-tail '(OP ... X) L)}}.
734Roughly analogous to {{member}} except for the default allowed types.
735
736<enscript highlight="scheme">
737(ck () (c-quote (c-member 'b '(a b c))))
738;; ==> '(b c)
739
740(ck () (c-quote (c-member 'x '(a b c))))
741;; ==> '#f
742
743(ck () (c-quote (c-member '(a b c)
744                          '((a) (x y z) (a b))
745                          '(c-u=))))
746;; ==> '((x y z) (a b))
747;; Because (c-u= '(a b c) '(x y z)) yields '#t
748</enscript>
749
750
751<syntax>(c-any '(OP ...) L)  →  result or '#f</syntax>
752
753Calls the operation on each value in the given list
754until it finds a result that is not {{'#f}}, then yields that result.
755Yields {{'#f}} if the predicate yields {{'#f}} for all items in the list,
756or if the list is empty.
757
758Analogous to {{any}} from SRFI-1.
759
760<enscript highlight="scheme">
761(ck () (c-quote (c-any '(c-pair?) '())))
762;; ==> '#f
763(ck () (c-quote (c-any '(c-pair?) '(a b c))))
764;; ==> '#f
765(ck () (c-quote (c-any '(c-pair?) '(a (b . c)))))
766;; ==> '#t
767
768(ck () (c-quote (c-any '(c-cons 'z) '(a b c))))
769;; ==> '(1 . a)
770;; Because (c-cons 'z 'a) yields a value that is not '#f.
771</enscript>
772
773
774<syntax>(c-every '(OP ...) L)  →  result or '#f</syntax>
775
776Calls the operation on each value in the given list
777until it finds a result that is {{'#f}}, then yields {{'#f}}.
778If the predicate yields a non-{{'#f}} value for every item in the list,
779this yields the result of calling the predicate on the last item.
780Yields {{'#t}} if the list is empty.
781
782Analogous to {{every}} from SRFI-1.
783
784<enscript highlight="scheme">
785(ck () (c-quote (c-every '(c-pair?) '())))
786;; ==> '#t
787(ck () (c-quote (c-every '(c-pair?) '(a (b . c)))))
788;; ==> '#f
789(ck () (c-quote (c-every '(c-pair?) '((a . b) (b . c)))))
790;; ==> '#t
791
792(ck () (c-quote (c-every '(c-cons 'z) '(a b c))))
793;; ==> '(z . c)
794;; Because all results were non-'#f and (c-cons 'z 'c) was the final operation.
795</enscript>
796
797
798<syntax>(c-assoc KEY ALIST)  →  pair or '#f</syntax>
799<syntax>(c-assoc KEY ALIST '(OP ...))  →  pair or '#f</syntax>
800
801Searches {{ALIST}} for the first pair whose car matches {{KEY}},
802then yields that pair.
803Yields {{'#f}} if no match is found.
804{{ALIST}} must be an association list, i.e. a list of pairs.
805
806Uses {{'(OP ...)}} for comparison,
807or {{'(c-sym-equal?)}} if {{'(OP ...)}} is omitted.
808
809Analogous to {{assoc}} from SRFI-1.
810
811<enscript highlight="scheme">
812(ck () (c-quote (c-assoc 'x '((a . 1) (b . 2) (a . 3)))))
813;; ==> '#f
814(ck () (c-quote (c-assoc 'a '((a . 1) (b . 2) (a . 3)))))
815;; ==> '(a . 1)
816(ck () (c-quote (c-assoc '(a) '((a . 1) (b . 2) ((a) . 3)))))
817;; ==> '((a) . 3)
818</enscript>
819
820
821<syntax>(c-alist-delete KEY ALIST)  →  list</syntax>
822<syntax>(c-alist-delete KEY ALIST '(OP ...))  →  list</syntax>
823
824Removes all pairs in {{ALIST}} whose car matches {{KEY}}.
825{{ALIST}} must be an association list, i.e. a list of pairs.
826
827Uses {{'(OP ...)}} for comparison,
828or {{'(c-sym-equal?)}} if {{'(OP ...)}} is omitted.
829
830Analogous to {{alist-delete}} from SRFI-1.
831Based on {{c-delete-assoc}} from the original implementation.
832
833<enscript highlight="scheme">
834(ck () (c-quote (c-alist-delete 'a '((a . 1) (b . 2) (a . 3) (c . 4)))))
835;; ==> '((b . 2) (c . 4)
836(ck () (c-quote (c-alist-delete '(a) '((a . 1) (b . 2) ((a) . 3)))))
837;; ==> '((a . 1) (b . 2))
838</enscript>
839
840
841==== Vector Processing
842
843<syntax>(c-vector X ...)  →  vector</syntax>
844
845Yields a vector containing the given items.
846Analogous to {{vector}}.
847
848
849<syntax>(c-list->vector L)  →  vector</syntax>
850
851Yields a vector containing the same items as the given list.
852Analogous to {{list->vector}} from SRFI-43.
853
854
855<syntax>(c-vector->list V)  →  list</syntax>
856
857Yields a list containing the same items as the given vector.
858Analogous to {{vector->list}} from SRFI-43.
859
860
861<syntax>(c-vector-reverse V)  →  vector</syntax>
862
863Yields the given vector in reverse order.
864Similar to {{vector-reverse-copy}} from SRFI-43,
865but does not take a start or end argument.
866
867
868<syntax>(c-vector-suffix V X ...)  →  vector</syntax>
869
870Yields the given vector with the extra arguments added to the end.
871
872<enscript highlight="scheme">
873(ck () (c-quote (c-vector-suffix '#(a b) 'c 'd)))
874;; ==> '#(a b c d)
875</enscript>
876
877
878<syntax>(c-vector-append V ...)  →  vector</syntax>
879
880Appends the given vectors.
881Analogous to {{vector-append}} from SRFI-43,
882but only accepts two vectors.
883
884<enscript highlight="scheme">
885(ck () (c-quote (c-vector-append)))
886;; ==> '#()
887
888(ck () (c-quote (c-vector-append '#(a b) '#(c d) '#(e f))))
889;; ==> '#(a b c d e f)
890</enscript>
891
892
893<syntax>(c-vector-map '(OP ...) V)  →  vector</syntax>
894
895Yields a vector by calling the quoted operation on each item in the given vector.
896The operation may have leading arguments.
897
898Analogous to {{vector-map}} from SRFI-43, but only accepts one vector.
899
900
901
902==== Unary Math
903
904The CK-macros in this section perform mathematical operations by treating lists as unary numbers.
905Unary math is pretty slow for large values or complex operations,
906but it is interesting, portable, and maybe even useful in some cases.
907
908Unary numbers are a way of representing non-negative integers as a list of a certain length.
909For example, the list {{'(a b c d e)}} means the number 5,
910and the list {{'()}} means the number 0.
911The contents of the list do not matter, only the length.
912Negative numbers and non-integral numbers cannot be represented in unary.
913
914
915<syntax>(c-u= U1 U2)  →  '#t or '#f</syntax>
916
917Unary equality.
918Yields {{'#t}} if the two lists have the same lengths,
919otherwise yields {{'#f}}.
920
921<enscript highlight="scheme">
922(ck () (c-quote (c-u= '(a b c) '(a b c))))
923;; ==> '#t
924(ck () (c-quote (c-u= '(1 2 3) '(a b c))))
925;; ==> '#t
926(ck () (c-quote (c-u= '(1 2) '(a b c))))
927;; ==> '#f
928</enscript>
929
930
931<syntax>(c-u< U1 U2)  →  '#t or '#f</syntax>
932
933Unary less-than.
934Yields {{'#t}} if the first list is shorter than the second list,
935otherwise yields {{'#f}}.
936
937<enscript highlight="scheme">
938(ck () (c-quote (c-u< '(1 2) '(a b c))))
939;; ==> '#t
940(ck () (c-quote (c-u< '(1 2 3) '(a b c))))
941;; ==> '#f
942</enscript>
943
944
945<syntax>(c-u<= U1 U2)  →  '#t or '#f</syntax>
946
947Unary less-than-or-equals.
948Yields {{'#t}} if first list is the same length or shorter than the second list,
949otherwise yields {{'#f}}.
950
951<enscript highlight="scheme">
952(ck () (c-quote (c-u<= '(1 2) '(a b c))))
953;; ==> '#t
954(ck () (c-quote (c-u<= '(1 2 3) '(a b c))))
955;; ==> '#t
956(ck () (c-quote (c-u<= '(1 2 3 4) '(a b c))))
957;; ==> '#f
958</enscript>
959
960
961<syntax>(c-u> U1 U2)  →  '#t or '#f</syntax>
962
963Unary greater-than.
964Yields {{'#t}} if the first list is longer than the second list,
965otherwise yields {{'#f}}.
966
967<enscript highlight="scheme">
968(ck () (c-quote (c-u> '(1 2 3 4) '(a b c))))
969;; ==> '#t
970(ck () (c-quote (c-u> '(1 2 3) '(a b c))))
971;; ==> '#f
972</enscript>
973
974
975<syntax>(c-u>= U1 U2)  →  '#t or '#f</syntax>
976
977Unary greater-than-or-equals.
978Yields {{'#t}} if first list is same length or longer than the second list,
979otherwise yields {{'#f}}.
980
981<enscript highlight="scheme">
982(ck () (c-quote (c-u>= '(1 2 3 4) '(a b c))))
983;; ==> '#t
984(ck () (c-quote (c-u>= '(1 2 3) '(a b c))))
985;; ==> '#t
986(ck () (c-quote (c-u>= '(1 2) '(a b c))))
987;; ==> '#f
988</enscript>
989
990
991<syntax>(c-uzero? U)  →  '#t or '#f</syntax>
992
993Unary {{zero?}}.
994Yields {{'#t}} if the list is empty, otherwise yields {{'#f}}.
995Same as {{c-null?}}.
996
997<enscript highlight="scheme">
998(ck () (c-quote (c-uzero? '())))
999;; ==> '#t
1000(ck () (c-quote (c-uzero? '(a))))
1001;; ==> '#f
1002</enscript>
1003
1004
1005<syntax>(c-ueven? U)  →  '#t or '#f</syntax>
1006
1007Unary {{even?}}.
1008Yields {{'#t}} if the given list's length is even
1009(i.e. a multiple of 2), otherwise yields {{'#f}}.
1010
1011<enscript highlight="scheme">
1012(ck () (c-quote (c-ueven? '())))
1013;; ==> '#t
1014(ck () (c-quote (c-ueven? '(a))))
1015;; ==> '#f
1016(ck () (c-quote (c-ueven? '(a b))))
1017;; ==> '#t
1018</enscript>
1019
1020
1021<syntax>(c-uodd? U)  →  '#t or '#f</syntax>
1022
1023Unary {{odd?}}.
1024Yields {{'#t}} if the given list's length is odd length
1025(i.e. not a multiple of 2), otherwise yields {{'#f}}.
1026
1027<enscript highlight="scheme">
1028(ck () (c-quote (c-uodd? '())))
1029;; ==> '#f
1030(ck () (c-quote (c-uodd? '(a))))
1031;; ==> '#t
1032(ck () (c-quote (c-uodd? '(a b))))
1033;; ==> '#f
1034</enscript>
1035
1036
1037<syntax>(c-u+ U1 U2)  →  list</syntax>
1038
1039Unary addition.
1040Same as {{c-append}}.
1041This was named {{c-add}} in the original implementation.
1042
1043<enscript highlight="scheme">
1044(ck () (c-quote (c-u+ '(a b) '(c))))
1045;; ==> '(a b c)
1046</enscript>
1047
1048
1049<syntax>(c-u- U1 U2)  →  list</syntax>
1050
1051Unary subtraction.
1052Drops an element from the front of the first list for each element in second list,
1053then yields the remaining list.
1054Negative numbers cannot be represented in unary,
1055so this yields '() if the second list is equal or longer than the first.
1056
1057<enscript highlight="scheme">
1058(ck () (c-quote (c-u- (c-list 'a 'b 'c 'd) '(x y))))
1059;; ==> '(c d)
1060
1061(ck () (c-quote (c-u- (c-list 'a 'b) (c-list 'x 'y 'z))))
1062;; ==> '()
1063;; Because negative numbers cannot be represented in unary.
1064</enscript>
1065
1066
1067<syntax>(c-u* U1 U2)  →  list</syntax>
1068
1069Unary multiplication.
1070Yields a list containing the contents of the first list,
1071repeated once for every item in the second list.
1072
1073Based on {{c-mul}} from the original implementation,
1074except the symbol 'u has no special significance,
1075and result is made from duplicating the first list.
1076
1077<enscript highlight="scheme">
1078(ck () (c-quote (c-u* '(a b) '(c d e))))
1079;; ==> '(a b a b a b)
1080</enscript>
1081
1082
1083<syntax>(c-u/ U1 U2)  →  list</syntax>
1084
1085Unary division.
1086Yields a list of two unary numbers,
1087representing the quotient and the remainder of the division.
1088
1089Given the second list has length {{N}},
1090the quotient will contain every {{N}}th item from the first list,
1091and the remainder will contain the tail of the first list.
1092Division by zero (empty list) is a syntax error.
1093
1094<enscript highlight="scheme">
1095(ck () (c-quote (c-u/ '(a b c d e f g h i j k)
1096                      '(x y z))))
1097;; ==> '((g d a) (j k))
1098;; Because 11 / 3 = 3 with a remainder of 2.
1099</enscript>
1100
1101
1102<syntax>(c-ufactorial U)  →  list</syntax>
1103
1104Unary factorial.
1105If the given list has length zero, yields the list {{'(u)}}.
1106If the given list has length one, yields the given list.
1107Otherwise, yields a list containing items of the given list repeated {{(N-1)!}} times,
1108where {{N}} is the length of the given list.
1109This was named {{c-fact}} in the original source.
1110
1111<enscript highlight="scheme">
1112(ck () (c-quote (c-ufactorial '(a b c))))
1113;; ==> '(a b c a b c)
1114;; Because 3! = 6.
1115</enscript>
1116
1117
1118<syntax>(c-udrop L U)  →  list</syntax>
1119
1120Drops up to U items from the front of the given list,
1121where U is a unary number.
1122
1123Same as {{c-u-}}.
1124Analogous to {{drop}} from SRFI-1,
1125but uses unary numbers,
1126and yields empty list if the list is too short.
1127
1128<enscript highlight="scheme">
1129(ck () (c-quote (c-udrop (c-list 'a 'b 'c 'd) '(x y))))
1130;; ==> '(c d)
1131(ck () (c-quote (c-udrop (c-list 'a 'b) (c-list 'x 'y 'z))))
1132;; ==> '()
1133</enscript>
1134
1135
1136<syntax>(c-utake L U)  →  list</syntax>
1137
1138Yields a list containing up to U items from the front of the given list,
1139where U is a unary number.
1140
1141Analogous to {{take}} from SRFI-1,
1142but uses unary numbers,
1143and yields the entire list if it is too short.
1144
1145<enscript highlight="scheme">
1146(ck () (c-quote (c-utake '(a b c d) '(x y z))))
1147;; ==> '(a b c)
1148(ck () (c-quote (c-utake '(a b) '(x y z))))
1149;; ==> '(a b)
1150</enscript>
Note: See TracBrowser for help on using the repository browser.