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

Last change on this file since 33159 was 33159, checked in by John Croisant, 4 years ago

ck-macros: Docs for new egg.

File size: 25.0 KB
Line 
1== ck-macros
2
3Composable Scheme macros based on the CK abstract machine.
4
5The ck-macros egg provides Oleg Kiselyov's CK-macro system, describe in the article,
6[[http://okmij.org/ftp/Scheme/macros.html#ck-macros|Applicative syntax-rules: macros that compose better]].
7
8This egg provides version 1.1 (April 2011) of the core {{ck}} macro,
9which is the latest version as of this writing.
10This egg also provides many useful (and some not-so-useful) predefined CK-macros.
11
12If you create a useful or interesting general-purpose CK-macro,
13or an improvement to an existing CK-macro,
14please contact the maintainer so your contribution can be added to the library.
15All source code (including contributions) is public domain.
16
17; Project / Source Code Repository : [[https://gitlab.com/jcroisant/ck-macros]]
18; Author : Oleg Kiselyov, with additional CK-macros and documentation by [[users/john-croisant|John Croisant]]
19; Egg Maintainer : [[users/john-croisant|John Croisant]]
20; License: Public Domain
21
22
23'''Table of Contents:'''
24[[toc:]]
25
26
27=== What are CK-macros?
28
29CK-macros are Scheme macros written to be compatible with with the core {{ck}} macro.
30
31The core {{ck}} macro is a {{syntax-rules}} macro which implements the CK abstract machine.
32The CK abstract machine is a computational model described by Matthias Felleisen and Daniel P. Friedman
33in the paper, "Control Operators, the SECD-Machine, and the Lambda-Calculus".
34Fortunately, you don't need to understand the paper in order to create or use CK-macros!
35
36Basically, the core {{ck}} macro does some clever rearranging to expand the CK-macro's arguments,
37allowing you to easily combine simple reusable macros to form more complex macros.
38This is very similar to the way Scheme makes it easy to combine simple resuable functions
39({{map}}, {{fold}}, {{cons}}, etc.) to create more complex functions.
40In fact, many useful Scheme functions can be translated to CK-macros,
41allowing you to achieve the same effect at macro-expansion time!
42
43CK-macros give you a lot of control over the macro expansion process,
44which allows you to implement many kinds of macros much more simply
45than you could with traditional style {{syntax-rules}} macros.
46You can even implement "higher-ordered macros" which take a macro as an argument.
47See {{c-map}} and {{c-fold}} for examples of higher-ordered macros.
48
49CK-macros are not as flexibile or powerful as
50CHICKEN's [[/manual/Macros|explicit and implicit renaming macros]],
51but CK-macros are much more portable.
52The core {{ck}} macro and most CK-macros are implemented using only {{syntax-rules}},
53which means they will work on any implementation of R5RS or later.
54
55
56=== How to write CK-macros
57
58Here is a basic template for CK-macros:
59
60<enscript highlight="scheme">
61(define-syntax c-foo
62  (syntax-rules (quote)
63    ((c-foo s 'input1 'input2 ...)
64     (ck s output))))
65</enscript>
66
67As you can see, a CK-macro is a macro that expands into a call to the core {{ck}} macro.
68The core {{ck}} macro does some clever rearranging under the hood
69to support composition with other CK-macros.
70
71CK-macros are usually defined using {{syntax-rules}} for maximum portability.
72But, it is also possible to write CK-macros using other macro systems,
73such as CHICKEN's [[/manual/Macros|explicit and implicit renaming macros]],
74as long as those macros expand into a call to the core {{ck}} macro.
75
76By convention, the names of CK-macros usually start with "c-",
77to distinguish them from non-CK macros or procedures with similar names.
78But, this naming convention is not required.
79
80CK-macros treat quoting specially, so you should include {{quote}} in the first argument to {{syntax-rules}}, the list of literal identifiers.
81
82The first argument to every CK-macro must be the stack, usually called {{s}}.
83The stack is used by the core {{ck}} macro to do its clever rearranging.
84Your CK-macro should not touch the stack, just pass it through to the core {{ck}} macro.
85
86Each {{'input}} is an argument passed to your macro.
87The core {{ck}} macro expands the arguments ahead of time (unless the argument is quoted),
88so the arguments will always be quoted values by the time your macro is expanded.
89Usually CK-macros are defined with their arguments quoted (as above),
90so that you can easily extract the unquoted value to use in your macro.
91
92Your macro should transform the {{input}}s in some way to produce the {{output}},
93which is passed to the core {{ck}} macro.
94The {{output}} must be either:
95
96* A quoted value, such as {{'a}}, {{'(+ 1 2)}}, {{'"foo"}}, {{'42}}, or {{'#t}}.
97* Or, an unquoted call to a CK-macro '''without the s argument''', such as {{(c-cons '+ '(1 2))}}.
98  Nested calls are allowed, such as {{(c-cons '+ (c-list '1 '2))}}.
99
100Quoting is how the core {{ck}} macro knows the difference between a value and a CK-macro call.
101Therefore, '''all values must be quoted''',
102even values which normally do not need to be quoted in Scheme code,
103such as strings, numbers, and booleans.
104
105Eventually, your CK-macro must expand into a call to the core {{ck}} macro
106with a quoted value.
107We say that the macro "yields" this quoted value.
108The quoted value is either used as an argument to another CK-macro,
109or if your CK-macro is the outer-most CK-macro call,
110then the core {{ck}} macro expands into the '''unquoted value'''.
111
112So, if your CK-macro yields the quoted value {{'(+ 1 2)}},
113and it is the outer-most CK-macro (not an argument to another CK-macro),
114the core {{ck}} macro will expand to the unquoted expression {{(+ 1 2)}},
115which would later be evaluated to the number 3.
116(If you want to yield a quoted form as the final result,
117use {{c-quote}} as the outer-most CK-macro.)
118
119See [[http://okmij.org/ftp/Scheme/macros.html#ck-macros|the original article]]
120or [[https://gitlab.com/jcroisant/ck-macros/blob/master/ck-portable.scm|the source code]]
121for many examples of CK-macros.
122
123
124=== Combining CK-macros with non-CK macros
125
126All CK-macros must evenutally expand to a call to the core {{ck}} macro.
127Therefore, many non-CK macros cannot be used ''inside'' CK-macros.
128
129But, it is always possible to write a non-CK macro which calls invokes a CK-macro.
130For example, if you are writing a macro for other people to use,
131you can create a convenience wrapper macro, like so:
132
133<enscript highlight="scheme">
134;;; Convenience wrapper around c-foo.
135(define-syntax foo
136  (syntax-rules ()
137    ((foo arg1 arg2 arg3)
138     (ck () (c-foo 'arg1 'arg2 'arg3)))))
139</enscript>
140
141Also, it is always possible for a CK-macro to expand into a call to a non-CK macro as its final result.
142For example:
143
144<enscript highlight="scheme">
145;;; Non-CK macro
146(define-syntax bar
147  (syntax-rules ()
148    ((bar a b c)
149     (+ a (* b c)))))
150
151;;; CK-macro
152(define-syntax c-fiz
153  (syntax-rules (quote)
154    ((c-fiz s 'a 'b 'c)
155     (ck s '(bar a b c)))))
156
157(ck () (c-fiz '1 '2 '3))
158;;; Expands to the expression (bar 1 2 3),
159;;; which expands to the expression (+ 1 (* 2 3)),
160;;; which evaluates to the number 7.
161</enscript>
162
163Finally, some non-CK macros can be used in a way that expands into a user-provided expression.
164These non-CK macros can therefore be used ''inside'' CK-macros,
165as long as they eventually expand into a call to the core {{ck}} macro.
166
167
168=== ck
169
170<syntax>(ck s 'v)</syntax>
171<syntax>(ck s (op ...))</syntax>
172
173This is the core {{ck}} macro, which implements the CK abstract machine.
174This macro's public interface has two shapes:
175one with a quoted value, and one with a CK-macro call.
176
177; 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)))}}.
178; '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.
179; (op ...) : A CK-macro call '''without the s argument''', such as {{(c-cons '+ '(1 2))}}.
180
181
182=== Portable CK-Macros
183
184The CK-macros in this section are defined using only standard R5RS features,
185such as {{syntax-rules}} and {{let-syntax}}.
186Therefore, these CK-macros will work with any implementation of R5RS or later.
187
188==== General
189
190<syntax>(c-quote X)  →  'X</syntax>
191
192Adds an extra level of quotation to the argument.
193This is useful for macros that should expand to a quoted value.
194
195<enscript highlight="scheme">
196;; Without c-quote
197(ck () (c-cons '+ '(1 2)))
198;; Expands to (+ 1 2), which evaluates to the number 3.
199
200;; With c-quote
201(ck () (c-quote (c-cons '+ '(1 2))))
202;; Expands to '(+ 1 2), a quoted list.
203</enscript>
204
205
206<syntax>(c-eval '(OP ...))  →  result</syntax>
207
208Takes a quoted operation and unquotes it,
209allowing the CK machine to expand it.
210Analogous to {{eval}}.
211
212<enscript highlight="scheme">
213(ck () (c-quote (c-eval '(c-cons 'a 'b))))
214;; ==> '(a . b)
215</enscript>
216
217
218<syntax>(c-call '(OP ...) X ...)  →  result</syntax>
219
220Like {{c-eval}}, but adds the given arguments on to the end of the operation.
221Analogous to a lambda call in normal Scheme code.
222
223<enscript highlight="scheme">
224(ck () (c-quote (c-call '(c-cons 'a) 'b)))
225;; ==> '(a . b)
226</enscript>
227
228
229<syntax>(c-apply '(OP ...) X ... '(Y ...))  →  result</syntax>
230
231Like {{c-call}}, but the last argument is a list of more arguments.
232Analogous to {{apply}}.
233
234<enscript highlight="scheme">
235(ck () (c-quote (c-apply '(c-list) 'a 'b '(c d))))
236;; ==> '(a b c d)
237</enscript>
238
239
240<syntax>(c-identity X)  →  X</syntax>
241
242Simply yields the value as given.
243Sometimes useful for higher-order macros like {{c-filter}}.
244
245<enscript highlight="scheme">
246(ck () (c-quote (c-identity 'a)))
247;; ==> 'a
248</enscript>
249
250
251==== Boolean Logic
252
253<syntax>(c-not X)  →  '#t or '#f</syntax>
254
255Yields {{'#t}} if the argument is {{'#f}}, otherwise yields {{'#f}}.
256Analogous to {{not}}.
257
258
259<syntax>(c-if TEST PASS FAIL)  →  PASS or FAIL</syntax>
260
261Conditional branching.
262Yields {{FAIL}} if {{TEST}} is {{'#f}} (or an operation that yields {{'#f}}).
263Otherwise yields {{PASS}}.
264
265Due to the way the CK machine works, both branches will be expanded,
266then the unneeded branch will be discarded.
267If you only want the needed branch to be expanded
268(e.g. because the branches are complex and slow to expand,
269or because it would be an error to expand the unneeded branch),
270use {{c-if/q}} instead.
271
272Analogous to
273{{(lambda (test pass fail) (if test pass fail))}}.
274
275<enscript highlight="scheme">
276(ck () (c-quote (c-if (c-pair? '(x))
277                      'pair
278                      'not-pair)))
279;; ==> 'pair
280
281(ck () (c-quote (c-if (c-pair? 'x)
282                      'pair
283                      'not-pair)))
284;; ==> 'not-pair
285</enscript>
286
287
288<syntax>(c-if/q 'TEST 'PASS 'FAIL)  →  PASS or FAIL</syntax>
289
290Similar to {{c-if}}, except that all the arguments must have an extra level of quoting,
291and only one branch will be expanded.
292This is more similar to how {{if}} behaves, but it is a bit awkward to use.
293
294Analogous to
295{{(lambda (test pass fail) (if (eval test) (eval pass) (eval fail)))}}
296
297<enscript highlight="scheme">
298(ck () (c-quote (c-if '(c-pair? '(x))
299                      '(c-car '(x))
300                      ''not-pair))
301;; ==> 'x
302
303(ck () (c-quote (c-if '(c-pair? 'x)
304                      '(c-car 'x)
305                      ''not-pair))
306;; ==> 'not-pair
307</enscript>
308
309
310<syntax>(c-or X ...)  →  item or '#f</syntax>
311
312Yields the first argument that is not {{'#f}}.
313Yields {{'#f}} if all of the arguments are {{'#f}},
314or if there are no arguments.
315
316Roughly analogous to {{or}}, except all arguments are expanded.
317If you only want to expand the arguments that are needed, use {{c-or/q}} instead.
318
319
320<syntax>(c-or/q 'X ...)  →  item or '#f</syntax>
321
322Similar to {{c-or}}, except that all the arguments must have an extra level of quoting,
323and the arguments will be expanded one at a time until a non-{{'#f}} value is found.
324This is more similar to how {{or}} behaves, but it is a bit awkward to use.
325
326
327<syntax>(c-and X ...)  →  item or '#f</syntax>
328
329If all arguments are not {{'#f}}, yields the last argument.
330If any of the arguments is {{'#f}}, yields {{'#f}}.
331If there are no arguments, yields {{'#t}}.
332
333Roughly analogous to {{and}}, except all arguments are expanded.
334If you only want to expand the arguments that are needed, use c-and/q instead.
335
336
337<syntax>(c-and/q X ...)  →  item or '#f</syntax>
338
339Similar to {{c-and}}, except that all the arguments must have an extra level of quoting,
340and the arguments will be expanded one at a time until a {{'#f}} value is found.
341This is more similar to how {{and}} behaves, but it is a bit awkward to use.
342
343
344<syntax>(c-null? X)  →  '#t or '#f</syntax>
345
346Yields {{'#t}} if {{X}} is the empty list, '().
347Otherwise yields {{'#f}}.
348Analogous to {{null?}}.
349
350
351<syntax>(c-pair? X)  →  '#t or '#f</syntax>
352
353Yields {{'#t}} if {{X}} is a dotted pair or a non-empty list.
354Otherwise yields {{'#f}}.
355Analogous to {{pair?}}.
356
357
358<syntax>(c-not-pair? X)  →  '#t or '#f</syntax>
359
360Opposite of {{c-pair?}}.
361Analogous to {{not-pair?}} from SRFI-1.
362
363
364<syntax>(c-boolean? X)  →  '#t or '#f</syntax>
365
366Yields {{'#t}} if {{X}} is either {{'#t}} or {{'#f}}.
367Otherwise yields {{'#f}}.
368Analogous to {{boolean?}}.
369
370
371<syntax>(c-sym-eq? X Y)  →  '#t or '#f</syntax>
372
373Yields {{'#t}} if {{X}} and {{Y}} are the same symbol, otherwise yields {{'#f}}.
374{{X}} should be a symbol.
375{{Y}} can be any value.
376Some Scheme implementations allow {{X}} to be other types,
377but this macro is only portable if {{X}} is a symbol.
378
379Roughly analogous to {{eq?}},
380except it only works (portably) with symbols.
381Based on {{symbol-eq?}} from the article.
382
383
384<syntax>(c-sym-equal? X Y)  →  '#t or '#f</syntax>
385
386Similar to c-sym-eq?, except it recursively compares lists and pairs.
387
388Roughly analogous to {{equal?}},
389except it only works (portably) with symbols, lists of symbols, and pairs of symbols.
390
391
392==== List Processing
393
394<syntax>(c-cons X Y)  →  pair</syntax>
395
396Yields a pair with the two given arguments.
397Analogous to {{cons}}.
398
399<enscript highlight="scheme">
400(ck () (c-quote (c-cons '"a" '1)))
401;; Expands to '("a" . 1).
402
403(ck () (c-quote (c-cons '+ '(1 2))))
404;; Expands to '(+ 1 2).
405
406(ck () (c-quote (c-cons '+ (c-cons '1 (c-cons '2 '())))))
407;; Also expands to '(+ 1 2).
408</enscript>
409
410
411<syntax>(c-list X ...)  →  list</syntax>
412
413Yields a list with the given arguments.
414Analogous to {{list}}.
415
416
417<syntax>(c-car P)  →  item</syntax>
418
419Yields the head of the given pair.
420Analogous to {{car}}.
421
422
423<syntax>(c-cdr P)  →  tail</syntax>
424
425Yields the tail of the given pair.
426Analogous to {{cdr}}.
427
428
429<syntax>(c-first   L)  →  item</syntax>
430<syntax>(c-second  L)  →  item</syntax>
431<syntax>(c-third   L)  →  item</syntax>
432<syntax>(c-fourth  L)  →  item</syntax>
433<syntax>(c-fifth   L)  →  item</syntax>
434<syntax>(c-sixth   L)  →  item</syntax>
435<syntax>(c-seventh L)  →  item</syntax>
436<syntax>(c-eighth  L)  →  item</syntax>
437<syntax>(c-ninth   L)  →  item</syntax>
438<syntax>(c-tenth   L)  →  item</syntax>
439
440Yields the Nth item of the given list.
441Fails if the list is too short.
442
443Analogous to {{first}} ... {{tenth}} from SRFI-1.
444
445<enscript highlight="scheme">
446(ck () (c-quote (c-first  '(a b c d e f g h i j k))))  ; ==> 'a
447(ck () (c-quote (c-second '(a b c d e f g h i j k))))  ; ==> 'b
448(ck () (c-quote (c-third  '(a b c d e f g h i j k))))  ; ==> 'c
449;;; ...
450(ck () (c-quote (c-tenth  '(a b c d e f g h i j k))))  ; ==> 'j
451</enscript>
452
453
454<syntax>(c-last L)  →  item</syntax>
455
456Yields the last value of the given list.
457Fails if the list is empty or is not a proper list.
458
459Analogous to {{last}} from SRFI-1.
460
461<enscript highlight="scheme">
462(ck () (c-quote (c-last '(a b c))))    ; ==> 'c
463(ck () (c-quote (c-last '(a b . c))))  ; ==> ERROR!
464</enscript>
465
466
467<syntax>(c-last-pair L)  →  pair</syntax>
468
469Yields the last pair of the given list.
470Fails if the list is empty.
471
472Analogous to {{last-pair}} from SRFI-1.
473
474<enscript highlight="scheme">
475(ck () (c-quote (c-last-pair '(a b c))))    ; ==> '(c)
476(ck () (c-quote (c-last-pair '(a b . c))))  ; ==> '(b . c)
477</enscript>
478
479
480<syntax>(c-drop1 L)  →  list</syntax>
481<syntax>(c-drop2 L)  →  list</syntax>
482<syntax>(c-drop3 L)  →  list</syntax>
483<syntax>(c-drop4 L)  →  list</syntax>
484<syntax>(c-drop5 L)  →  list</syntax>
485
486Drops a predefined number of items from the front of the given list.
487Fails if the list is too short.
488
489Analogous to {{(drop L N)}} from SRFI-1.
490See also {{c-udrop}}.
491
492<enscript highlight="scheme">
493(ck () (c-quote (c-drop1 '(a b c d e f g))))  ; ==> '(b c d e f g)
494(ck () (c-quote (c-drop2 '(a b c d e f g))))  ; ==> '(c d e f g)
495(ck () (c-quote (c-drop3 '(a b c d e f g))))  ; ==> '(d e f g)
496(ck () (c-quote (c-drop4 '(a b c d e f g))))  ; ==> '(e f g)
497(ck () (c-quote (c-drop5 '(a b c d e f g))))  ; ==> '(f g)
498</enscript>
499
500
501<syntax>(c-take1 L)  →  list</syntax>
502<syntax>(c-take2 L)  →  list</syntax>
503<syntax>(c-take3 L)  →  list</syntax>
504<syntax>(c-take4 L)  →  list</syntax>
505<syntax>(c-take5 L)  →  list</syntax>
506
507Yields a list containing a predefined number of items from the front of the given list.
508Fails if the list is too short.
509
510Analogous to {{(take L N)}} from SRFI-1.
511See also {{c-utake}}.
512
513<enscript highlight="scheme">
514(ck () (c-quote (c-take1 '(a b c d e f g))))  ; ==> '(a)
515(ck () (c-quote (c-take2 '(a b c d e f g))))  ; ==> '(a b)
516(ck () (c-quote (c-take3 '(a b c d e f g))))  ; ==> '(a b c)
517(ck () (c-quote (c-take4 '(a b c d e f g))))  ; ==> '(a b c d)
518(ck () (c-quote (c-take5 '(a b c d e f g))))  ; ==> '(a b c d e)
519</enscript>
520
521
522<syntax>(c-reverse L)  →  list</syntax>
523
524Yields the given list in reverse order.
525Fails if the list is not a proper list.
526Analogous to {{reverse}}.
527
528
529<syntax>(c-suffix L X ...)  →  list</syntax>
530
531Yields the given list with the extra arguments added to the end.
532{{(c-suffix '(1 2) '3 '4)}} is equivalent to {{(c-append '(1 2) '(3 4))}}.
533
534
535<syntax>(c-append L1 L2)  →  list</syntax>
536
537Appends the two given lists.
538Analogous to {{append}}.
539
540<enscript highlight="scheme">
541(ck () (c-quote (c-append '(define foo) '((+ 1 2)))))
542;; ==> '(define foo (+ 1 2 3))
543
544(ck () (c-quote (c-append '(+) (c-append '(1) '(2)))))
545;; ==> '(+ 1 2)
546</enscript>
547
548
549<syntax>(c-append-map '(OP ...) L)  →  list</syntax>
550
551Yields a list by calling the quoted operation on each item in the list,
552then appending the results.
553The operation must be a CK-macro that yields a list.
554The operation may have leading arguments.
555
556Analogous to {{append-map}} from SFRI-1.
557This was named {{c-concatMap}} in the article.
558
559<enscript highlight="scheme">
560(ck () (c-quote (c-append-map '(c-list 'a 'b) '(1 2))))
561;; ==> '(a b 1 a b 2)
562</enscript>
563
564
565<syntax>(c-map '(OP ...) L)  →  list</syntax>
566
567Yields a list by calling the quoted operation on each item in the given list.
568The operation may have leading arguments.
569Analogous to {{map}}.
570
571<enscript highlight="scheme">
572(ck () (c-quote (c-map '(c-cons 'a) '(1 2))))
573;; ==> '((a . 1) (a . 2))
574</enscript>
575
576
577<syntax>(c-fold '(OP ...) INIT L)  →  result</syntax>
578
579Yield a value by repeatedly calling the quoted operation
580with each item from the list plus the previous result.
581
582The operation is first called with two arguments,
583the first item of the list and the initial value.
584Then, the operation is called with the next item of the list and the previous result.
585
586If list is empty, yields {{INIT}}.
587
588Analogous to {{fold}} from SRFI-1.
589
590
591<syntax>(c-filter '(OP ...) L)  →  list</syntax>
592
593Yields a list by calling the quoted operation on each item in the given list,
594and discarding any item for which the test yields {{'#f}}.
595Analogous to {{filter}} from SRFI-1.
596
597
598<syntax>(c-remove '(OP ...) L)  →  list</syntax>
599
600Opposite of c-filter.
601Discards items that pass the test, keeps items that fail the test.
602Analogous to {{remove}} from SRFI-1.
603
604
605<syntax>(c-find '(OP ...) L)  →  item or '#f</syntax>
606
607Yields the first item in the given list that passes the predicate operation
608(i.e. the predicate yields a non-{{'#f}} value).
609Yields {{'#f}} if no items pass the predicate.
610
611Analogous to {{find}} from SRFI-1.
612
613
614<syntax>(c-find-tail '(OP ...) L)  →  pair or '#f</syntax>
615
616Yields the first pair in the list for which the head of the pair passes the predicate operation
617(i.e. the predicate yields a non-{{'#f}} value).
618Yields {{'#f}} if no items pass the predicate.
619
620Analogous to {{find-tail}} from SRFI-1.
621
622
623<syntax>(c-sym-member X L)  →  '#t or '#f</syntax>
624
625Yields {{'#t}} if the list contains the given symbol, list of symbols,
626or pair of symbols, using {{c-sym-equal?}} for comparison.
627Otherwise yields {{'#f}}.
628
629Roughly analogous to {{member}}.
630
631
632<syntax>(c-any '(OP ...) L)  →  result or '#f</syntax>
633
634Calls the operation on each value in the given list
635until it finds a result that is not {{'#f}}, then yields that result.
636Yields {{'#f}} if the predicate yields {{'#f}} for all items in the list,
637or if the list is empty.
638
639Analogous to {{any}} from SRFI-1.
640
641
642<syntax>(c-every '(OP ...) L)  →  result or '#f</syntax>
643
644Calls the operation on each value in the given list
645until it finds a result that is {{'#f}}, then yields {{'#f}}.
646If the predicate yields a non-{{'#f}} value for every item in the list,
647this yields the result of calling the predicate on the last item.
648Yields {{'#t}} if the list is empty.
649
650Analogous to {{every}} from SRFI-1.
651
652
653<syntax>(c-assoc KEY ALIST)  →  pair or '#f</syntax>
654<syntax>(c-assoc KEY ALIST '(OP ...))  →  pair or '#f</syntax>
655
656Yields the first pair in {{ALIST}} whose car matches {{KEY}},
657or {{'#f}} if no match is found.
658Uses {{'(OP ...)}} for comparison,
659or {{'(c-sym-equal?)}} if {{'(OP ...)}} is omitted.
660
661Analogous to {{assoc}} from SRFI-1.
662
663
664<syntax>(c-alist-delete KEY ALIST)  →  list</syntax>
665<syntax>(c-alist-delete KEY ALIST '(OP ...))  →  list</syntax>
666
667Removes all pairs in {{ALIST}} whose car matches {{KEY}}.
668Uses {{'(OP ...)}} for comparison,
669or {{'(c-sym-equal?)}} if {{'(OP ...)}} is omitted.
670
671Analogous to {{alist-delete}} from SRFI-1.
672Based on {{c-delete-assoc}} from the article.
673
674
675
676==== Unary Math
677
678The CK-macros in this section perform mathematical operations by treating lists as unary numbers.
679Unary math is pretty slow for large values or complex operations,
680but it is interesting, portable, and maybe even useful in some cases.
681
682Unary numbers are a way of representing non-negative integers as a list of a certain length.
683For example, the list {{'(a b c d e)}} means the number 5,
684and the list {{'()}} means the number 0.
685The contents of the list do not matter, only the length.
686Negative numbers and non-integral numbers cannot be represented in unary.
687
688
689<syntax>(c-u= U1 U2)  →  '#t or '#f</syntax>
690
691Unary equality.
692Yields {{'#t}} if the two lists have the same lengths,
693otherwise yields {{'#f}}.
694
695
696<syntax>(c-u< U1 U2)  →  '#t or '#f</syntax>
697
698Unary less-than.
699Yields {{'#t}} if the first list is shorter than the second list,
700otherwise yields {{'#f}}.
701
702
703<syntax>(c-u<= U1 U2)  →  '#t or '#f</syntax>
704
705Unary less-than-or-equals.
706Yields {{'#t}} if first list is the same length or shorter than the second list,
707otherwise yields {{'#f}}.
708
709
710<syntax>(c-u> U1 U2)  →  '#t or '#f</syntax>
711
712Unary greater-than.
713Yields {{'#t}} if the first list is longer than the second list,
714otherwise yields {{'#f}}.
715
716
717<syntax>(c-u>= U1 U2)  →  '#t or '#f</syntax>
718
719Unary greater-than-or-equals.
720Yields {{'#t}} if first list is same length or longer than the second list,
721otherwise yields {{'#f}}.
722
723
724<syntax>(c-uzero? U)  →  '#t or '#f</syntax>
725
726Unary {{zero?}}.
727Yields {{'#t}} if the list is empty, otherwise yields {{'#f}}.
728Same as {{c-null?}}.
729
730
731<syntax>(c-ueven? U)  →  '#t or '#f</syntax>
732
733Unary {{even?}}.
734Yields {{'#t}} if the given list's length is even
735(i.e. a multiple of 2), otherwise yields {{'#f}}.
736
737
738<syntax>(c-uodd? U)  →  '#t or '#f</syntax>
739
740Unary {{odd?}}.
741Yields {{'#t}} if the given list's length is odd length
742(i.e. not a multiple of 2), otherwise yields {{'#f}}.
743
744
745<syntax>(c-u+ U1 U2)  →  list</syntax>
746
747Unary addition.
748Same as {{c-append}}.
749This was named {{c-add}} in the article.
750
751
752<syntax>(c-u- U1 U2)  →  list</syntax>
753
754Unary subtraction.
755Drops an element from the front of the first list for each element in second list,
756then yields the remaining list.
757Negative numbers cannot be represented in unary,
758so this yields '() if the second list is equal or longer than the first.
759
760
761<syntax>(c-u* U1 U2)  →  list</syntax>
762
763Unary multiplication.
764Yields a list containing the contents of the first list,
765repeated once for every item in the second list.
766
767Based on {{c-mul}} from the article,
768except the symbol 'u has no special significance,
769and result is made from duplicating the first list.
770
771
772<syntax>(c-u/ U1 U2)  →  list</syntax>
773
774Unary division.
775Yields a list of two unary numbers,
776representing the quotient and the remainder of the division.
777
778Given the second list has length {{N}},
779the quotient will contain every {{N}}th item from the first list,
780and the remainder will contain the tail of the first list.
781Division by zero (empty list) is a syntax error.
782
783
784<syntax>(c-ufactorial U)  →  list</syntax>
785
786Unary factorial.
787If the given list has length zero, yields the list {{'(u)}}.
788If the given list has length one, yields the given list.
789Otherwise, yields a list containing items of the given list repeated {{(N-1)!}} times,
790where {{N}} is the length of the given list.
791This was named {{c-fact}} in the original source.
792
793
794<syntax>(c-udrop L U)  →  list</syntax>
795
796Drops up to U items from the front of the given list,
797where U is a unary number.
798
799Analogous to {{drop}} from SRFI-1,
800but uses unary numbers,
801and yields empty list if the list is too short.
802
803
804<syntax>(c-utake L U)  →  list</syntax>
805
806Yields a list containing up to U items from the front of the given list,
807where U is a unary number.
808
809Analogous to {{take}} from SRFI-1,
810but uses unary numbers,
811and yields the entire list if it is too short.
Note: See TracBrowser for help on using the repository browser.