This is an archive of the ck-macros page from the CHICKEN Scheme wiki. You can view the latest version at: http://wiki.call-cc.org/eggref/4/ck-macros == ck-macros Composable Scheme macros based on the CK abstract machine. This egg is based on the CK-macro system described in "[[http://okmij.org/ftp/Scheme/macros.html#ck-macros|Applicative syntax-rules: macros that compose better]]" by Oleg Kiselyov. This egg provides the core {{ck}} macro, plus many useful (and some not-so-useful) predefined CK-macros. If you create a useful or interesting general-purpose CK-macro, or an improvement to an existing CK-macro, please contact the maintainer (John) so your contribution can be added to the egg. All source code (including contributions) is public domain. ; Project / Source Code Repository: [[https://gitlab.com/jcroisant/ck-macros]] ; Maintainer: [[/users/john-croisant|John Croisant]] ; Based on work by: Oleg Kiselyov ; License: Public Domain '''Table of Contents''' [[toc:]] === Version History ; 0.1.0 (2016-02-06) : Initial release. Includes version 1.1 (April 2011) of the core {{ck}} macro. Includes many CK-macros. For more information about what changed in each version, see the [[https://gitlab.com/jcroisant/ck-macros/blob/master/CHANGELOG.md|CHANGELOG]]. === What are CK-macros? CK-macros are Scheme macros written to be compatible with with the core {{ck}} macro. The core {{ck}} macro is a {{syntax-rules}} macro which implements the CK abstract machine. The CK abstract machine is a theoretical model of computation, described in the paper "Control Operators, the SECD-Machine, and the Lambda-Calculus" by Matthias Felleisen and Daniel P. Friedman. But, you don't need to read or understand the paper in order to create or use CK-macros! Basically, a CK-macro leverages the core {{ck}} macro to recursively expand the CK-macros's arguments first, before the CK-macro itself is expanded. This gives you more control over the macro expansion process, allowing you to easily combine simple reusable macros to form more complex macros. This is very similar to the way Scheme allows you to easily combine simple resuable functions ({{map}}, {{fold}}, {{cons}}, etc.) to create more complex functions. In fact, many useful Scheme functions can be translated to CK-macros, allowing you to portably achieve the same effect at macro-expansion time. You can even implement "higher-ordered macros" which take a macro as an argument. See {{c-map}} and {{c-fold}} for examples of higher-ordered macros. CK-macros are not as flexibile or powerful as CHICKEN's [[/manual/Macros|explicit and implicit renaming macros]], but CK-macros are much more portable. The [[#ck|core {{ck}} macro]] and all the macros in the [[#portable-ck-macros|Portable CK-Macros]] section are implemented using only standard R5RS features, such as {{syntax-rules}} and {{let-syntax}}. This means they will work on any implementation of R5RS or later. === How to write CK-macros Here is a basic template for CK-macros: (define-syntax c-foo (syntax-rules (quote) ((c-foo s 'input1 'input2 ...) (ck s output)))) A CK-macro is just a normal macro that expands to a call to the core {{ck}} macro. To be portable, CK-macros are usually written using {{syntax-rules}}. But, you can write CK-macros using other macro systems, such as CHICKEN's [[/manual/Macros|explicit and implicit renaming macros]], as long your macro eventually expands into a call to the core {{ck}} macro. By convention, the names of CK-macros usually start with "c-", to distinguish them from non-CK macros or procedures with similar names. But, this naming convention is not required. CK-macros treat quoting specially, so you should have {{quote}} in the list of literal identifiers (the first argument to {{syntax-rules}}). You can also have other literal identifiers if needed. Every CK-macro's first argument must be the stack, usually called {{s}}. The stack is used internally by the core {{ck}} macro while recursively expanding macro arguments. Your CK-macro should not touch the stack, only pass it through to the core {{ck}} macro. Each {{'input}} is an argument passed to your macro. Your macro can have any number of input arguments, and they can be named whatever you want. They can also be lists or patterns, allowing you to destructure the arguments, as is often done with {{syntax-rules}} macros. The core {{ck}} macro expands the input arguments ahead of time, so the arguments will always be quoted values by the time your macro is expanded. Usually CK-macros are defined with their input arguments quoted (as above), so that you can easily destructure the input to use in your macro. You may recall that {{'a}} is translated by the reader to {{(quote a)}}. So, the above example is exactly the same as: (define-syntax c-foo (syntax-rules (quote) ((c-foo s (quote input1) (quote input2) ...) (ck s output)))) When written in this way, it is easier to see that {{input1}} and {{input2}} are merely placeholders in the {{syntax-rules}} pattern. (This is also why you must tell {{syntax-rules}} that {{quote}} is a literal identifier. Otherwise, {{syntax-rules}} would treat {{quote}} as a placeholder, too.) Your macro should transform the {{input}}s in some way to produce the {{output}}, which is passed to the core {{ck}} macro. The {{output}} must be either: * A quoted value, such as {{'a}}, {{'(+ 1 2)}}, {{'"foo"}}, {{'42}}, or {{'#t}}. * Or, an unquoted call to a CK-macro '''without the s argument''', such as {{(c-cons '+ '(1 2))}}. Nested calls are allowed, such as {{(c-cons '+ (c-list '1 '2))}}. Quoting is how the core {{ck}} macro knows the difference between a value and a CK-macro call. Therefore, '''all values must be quoted''', even values which normally do not need to be quoted in Scheme code, such as strings, numbers, and booleans. Eventually, your CK-macro must expand into a call to the core {{ck}} macro with a quoted value. We say that the macro "yields" this quoted value. The quoted value is either used as an argument to another CK-macro, or if your CK-macro is the outer-most CK-macro call, then the core {{ck}} macro expands into the '''unquoted value'''. So, if your CK-macro yields the quoted value {{'(+ 1 2)}}, and it is the outer-most CK-macro (not an argument to another CK-macro), the core {{ck}} macro will expand to the unquoted expression {{(+ 1 2)}}, which would later be evaluated to the number 3. (If you want to yield a quoted form as the final result, use {{c-quote}} as the outer-most CK-macro.) See [[http://okmij.org/ftp/Scheme/macros.html#ck-macros|the original article]] or [[https://gitlab.com/jcroisant/ck-macros/blob/master/ck-portable.scm|the source code]] for many examples of CK-macros. === Combining CK and non-CK macros The arguments to a CK-macro must either be a quoted value or a call to a CK-macro (i.e. a macro that expands to a call to the core {{ck}} macro). Therefore, most non-CK macros and special forms cannot be used as arguments to a CK-macro. Some non-CK macros can be used in a way that expands into a user-provided expression. It is therefore possible for these non-CK macros to be used as arguments CK-macros, as long as they eventually expand into a call to the core {{ck}} macro. It is possible to write a non-CK macro which invokes a CK-macro via the core {{ck}} macro. For example, if you are writing a macro for other people to use, you can create a convenience wrapper macro, like so: ;;; Convenience wrapper around c-foo. (define-syntax foo (syntax-rules () ((foo arg1 arg2 arg3) (ck () (c-foo 'arg1 'arg2 'arg3))))) Also, it is possible for a CK-macro to expand into a call to a non-CK macro as its final result, or as part of the body of its final result. For example: (ck () (c-list 'when (c-list '< '1 '2) (c-list 'print '"Yay!"))) ;;; Expands to the expression (when (< 1 2) (print "Yay!")). === ck (ck s 'v) (ck s (op ...)) This is the core {{ck}} macro, which implements the CK abstract machine. This macro's public interface has two shapes: one with a quoted value, and one with a CK-macro call. ; 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)))}}. ; '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. ; (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))}}. === Portable CK-Macros The CK-macros in this section are defined using only standard R5RS features, such as {{syntax-rules}} and {{let-syntax}}. So, these CK-macros will work on any implementation of R5RS or later. ==== General (c-quote X) → 'X Adds an extra level of quotation to the argument. This is useful for macros that should expand to a quoted value. ;; Without c-quote (ck () (c-cons '+ '(1 2))) ;; Expands to (+ 1 2), which evaluates to the number 3. ;; With c-quote (ck () (c-quote (c-cons '+ '(1 2)))) ;; Expands to '(+ 1 2), a quoted list. (c-eval '(OP ...)) → result Takes a quoted operation and unquotes it, allowing the CK machine to expand it. Analogous to {{eval}}. (ck () (c-quote (c-eval '(c-cons 'a 'b)))) ;; ==> '(a . b) (c-call '(OP ...) X ...) → result Like {{c-eval}}, but adds the given arguments on to the end of the operation. Analogous to a lambda call in normal Scheme code. (ck () (c-quote (c-call '(c-cons 'a) 'b))) ;; ==> '(a . b) (c-apply '(OP ...) X ... '(Y ...)) → result Like {{c-call}}, but the last argument is a list of more arguments. Analogous to {{apply}}. (ck () (c-quote (c-apply '(c-list) 'a 'b '(c d)))) ;; ==> '(a b c d) (c-identity X) → X Simply yields the value as given. Sometimes useful for higher-order macros like {{c-filter}}. (ck () (c-quote (c-identity 'a))) ;; ==> 'a ==== Boolean Logic (c-not X) → '#t or '#f Yields {{'#t}} if the argument is {{'#f}}, otherwise yields {{'#f}}. Analogous to {{not}}. (c-if TEST PASS FAIL) → PASS or FAIL Conditional branching. If {{TEST}} is {{'#f}}, this yields {{FAIL}}. Otherwise it yields {{PASS}}. Due to the way the CK machine works, both branches will be expanded, then the unneeded branch will be discarded. If you only want the needed branch to be expanded (e.g. because the branches are complex and slow to expand, or because it would be an error to expand the unneeded branch), use {{c-if*}} instead. Analogous to {{(lambda (test pass fail) (if test pass fail))}}. (ck () (c-quote (c-if (c-pair? '(x)) 'pair 'not-pair))) ;; ==> 'pair (ck () (c-quote (c-if (c-pair? 'x) 'pair 'not-pair))) ;; ==> 'not-pair (c-if* TEST 'PASS 'FAIL) → PASS or FAIL Similar to {{c-if}}, except that the branches must have an extra level of quoting, and only one branch will be expanded. This is more similar to how {{if}} behaves, but it is a bit awkward to use. Analogous to {{(lambda (test pass fail) (if test (eval pass) (eval fail)))}} (ck () (c-quote (c-if (c-pair? '(x)) '(c-car '(x)) ''not-pair)) ;; ==> 'x (ck () (c-quote (c-if (c-pair? 'x) '(c-car 'x) ''not-pair)) ;; ==> 'not-pair (c-or X ...) → item or '#f Yields the first argument that is not {{'#f}}. Yields {{'#f}} if all of the arguments are {{'#f}}, or if there are no arguments. Roughly analogous to {{or}}, except all arguments are expanded. If you only want to expand the arguments that are needed, use {{c-or*}} instead. (c-or* 'X ...) → item or '#f Similar to {{c-or}}, except that all the arguments must have an extra level of quoting, and the arguments will be expanded one at a time until a non-{{'#f}} value is found. This is more similar to how {{or}} behaves, but it is a bit awkward to use. (c-and X ...) → item or '#f If all arguments are not {{'#f}}, yields the last argument. If any of the arguments is {{'#f}}, yields {{'#f}}. If there are no arguments, yields {{'#t}}. Roughly analogous to {{and}}, except all arguments are expanded. If you only want to expand the arguments that are needed, use {{c-and*}} instead. (c-and* X ...) → item or '#f Similar to {{c-and}}, except that all the arguments must have an extra level of quoting, and the arguments will be expanded one at a time until a {{'#f}} value is found. This is more similar to how {{and}} behaves, but it is a bit awkward to use. (c-null? X) → '#t or '#f Yields {{'#t}} if {{X}} is the empty list, {{'()}}. Otherwise yields {{'#f}}. Analogous to {{null?}}. (c-pair? X) → '#t or '#f Yields {{'#t}} if {{X}} is a dotted pair or a non-empty list. Otherwise yields {{'#f}}. Analogous to {{pair?}}. (c-not-pair? X) → '#t or '#f Opposite of {{c-pair?}}. Analogous to {{not-pair?}} from SRFI-1. (c-vector? X) → '#t or '#f Yields {{'#t}} if {{X}} is a vector. Otherwise yields {{'#f}}. Analogous to {{vector?}}. (ck () (c-quote (c-vector? '#(a)))) ;; ==> '#t (c-boolean? X) → '#t or '#f Yields {{'#t}} if {{X}} is either {{'#t}} or {{'#f}}. Otherwise yields {{'#f}}. Analogous to {{boolean?}}. (c-sym-eq? X Y) → '#t or '#f Yields {{'#t}} if {{X}} and {{Y}} are the same symbol, otherwise yields {{'#f}}. {{X}} should be a symbol. {{Y}} can be any value. Some Scheme implementations allow {{X}} to be other types, but this macro is only portable if {{X}} is a symbol. Roughly analogous to {{eq?}}, except it only works (portably) with symbols. Based on {{symbol-eq?}} from the original implementation. (c-sym-equal? X Y) → '#t or '#f Similar to {{c-sym-eq?}}, except it recursively compares pairs, lists, and vectors. Roughly analogous to {{equal?}}, except it only works (portably) with symbols, pairs, lists, vectors, and nested combinations of those things. ==== List Processing (c-cons X Y) → pair Yields a pair with the two given arguments. Analogous to {{cons}}. (ck () (c-quote (c-cons '"a" '1))) ;; Expands to '("a" . 1). (ck () (c-quote (c-cons '+ '(1 2)))) ;; Expands to '(+ 1 2). (ck () (c-quote (c-cons '+ (c-cons '1 (c-cons '2 '()))))) ;; Also expands to '(+ 1 2). (c-list X ...) → list Yields a list containing the given items. Analogous to {{list}}. (ck () (c-quote (c-list))) ;; ==> '() (ck () (c-quote (c-list 'a 'b 'c))) ;; ==> '(a b c) (c-car P) → item Yields the head of the given pair. Analogous to {{car}}. (ck () (c-quote (c-car '(a . b)))) ;; ==> 'a (ck () (c-quote (c-car '(a b)))) ;; ==> 'a (c-cdr P) → tail Yields the tail of the given pair. Analogous to {{cdr}}. (ck () (c-quote (c-cdr '(a . b)))) ;; ==> 'b (ck () (c-quote (c-cdr '(a b)))) ;; ==> '(b) (c-first L) → item (c-second L) → item (c-third L) → item (c-fourth L) → item (c-fifth L) → item (c-sixth L) → item (c-seventh L) → item (c-eighth L) → item (c-ninth L) → item (c-tenth L) → item Yields the Nth item of the given list. Fails if the list is too short. Analogous to {{first}} ... {{tenth}} from SRFI-1. (ck () (c-quote (c-first '(a b c d e f g h i j k)))) ; ==> 'a (ck () (c-quote (c-second '(a b c d e f g h i j k)))) ; ==> 'b (ck () (c-quote (c-third '(a b c d e f g h i j k)))) ; ==> 'c ;;; ... (ck () (c-quote (c-tenth '(a b c d e f g h i j k)))) ; ==> 'j (c-last L) → item Yields the last value of the given list. Fails if the list is empty or is not a proper list. Analogous to {{last}} from SRFI-1. (ck () (c-quote (c-last '(a b c)))) ; ==> 'c (ck () (c-quote (c-last '(a b . c)))) ; ==> ERROR! (c-last-pair L) → pair Yields the last pair of the given list. Fails if the list is empty. Analogous to {{last-pair}} from SRFI-1. (ck () (c-quote (c-last-pair '(a b c)))) ; ==> '(c) (ck () (c-quote (c-last-pair '(a b . c)))) ; ==> '(b . c) (c-drop1 L) → list (c-drop2 L) → list (c-drop3 L) → list (c-drop4 L) → list (c-drop5 L) → list Drops a predefined number of items from the front of the given list. Fails if the list is too short. See also {{c-udrop}}. Analogous to {{(drop L N)}} from SRFI-1. (ck () (c-quote (c-drop1 '(a b c d e f g)))) ; ==> '(b c d e f g) (ck () (c-quote (c-drop2 '(a b c d e f g)))) ; ==> '(c d e f g) (ck () (c-quote (c-drop3 '(a b c d e f g)))) ; ==> '(d e f g) (ck () (c-quote (c-drop4 '(a b c d e f g)))) ; ==> '(e f g) (ck () (c-quote (c-drop5 '(a b c d e f g)))) ; ==> '(f g) (c-take1 L) → list (c-take2 L) → list (c-take3 L) → list (c-take4 L) → list (c-take5 L) → list Yields a list containing a predefined number of items from the front of the given list. Fails if the list is too short. See also {{c-utake}}. Analogous to {{(take L N)}} from SRFI-1. (ck () (c-quote (c-take1 '(a b c d e f g)))) ; ==> '(a) (ck () (c-quote (c-take2 '(a b c d e f g)))) ; ==> '(a b) (ck () (c-quote (c-take3 '(a b c d e f g)))) ; ==> '(a b c) (ck () (c-quote (c-take4 '(a b c d e f g)))) ; ==> '(a b c d) (ck () (c-quote (c-take5 '(a b c d e f g)))) ; ==> '(a b c d e) (c-reverse L) → list Yields the given list in reverse order. Fails if the list is not a proper list. Analogous to {{reverse}}. (ck () (c-quote (c-reverse '(a b c)))) ;; ==> '(c b a) (c-suffix L X ...) → list Yields the given list with the extra arguments added to the end. (ck () (c-quote (c-suffix '(a) 'b 'c))) ;; ==> '(a b c) (c-append L ...) → list Appends the given lists. Analogous to {{append}}. (ck () (c-quote (c-append))) ;; ==> '() (ck () (c-quote (c-append '(+) (c-append '(1) '(2))))) ;; ==> '(+ 1 2) (ck () (c-quote (c-append '(define foo) '((+ 1 2))))) ;; ==> '(define foo (+ 1 2 3)) (c-append-map '(OP ...) L) → list Yields a list by calling the quoted operation on each item in the list, then appending the results. The operation must be a CK-macro that yields a list. The operation may have leading arguments. Analogous to {{append-map}} from SFRI-1, but only accepts one list. This was named {{c-concatMap}} in the original implementation. (ck () (c-quote (c-append-map '(c-list 'a 'b) '(1 2)))) ;; ==> '(a b 1 a b 2) (c-map '(OP ...) L) → list Yields a list by calling the quoted operation on each item in the given list. The operation may have leading arguments. Analogous to {{map}}, but only accepts one list. (ck () (c-quote (c-map '(c-cons 'a) '(1 2)))) ;; ==> '((a . 1) (a . 2)) (c-fold '(OP ...) INIT L) → result Yield a value by repeatedly calling the quoted operation with each item from the list plus the previous result. If the list is empty, yields {{INIT}}. Otherwise, the operation is first called with two arguments: the first item of the list, and INIT. Then, the operation is repeatedly called with the next item of the list and the previous result, until it reaches the end of the list. Yields the final result. Analogous to {{fold}} from SRFI-1, but only accepts one list. (ck () (c-quote (c-fold '(c-cons) '(x) '()))) ;; ==> '(x) (ck () (c-quote (c-fold '(c-cons) '(x) '(a b c d e f)))) ;; ==> '(f e d c b a x) (c-filter '(OP ...) L) → list Yields a list by calling the quoted operation on each item in the given list, and discarding any item for which the test yields {{'#f}}. Analogous to {{filter}} from SRFI-1. (ck () (c-quote (c-filter '(c-pair?) '(a (b . c) 1 (d e) #t)))) ;; ==> '((b . c) (d e)) (c-remove '(OP ...) L) → list Opposite of {{c-filter}}. Discards items that pass the test, keeps items that fail the test. Analogous to {{remove}} from SRFI-1. (ck () (c-quote (c-remove '(c-pair?) '(a (b . c) 1 (d e) #t)))) ;; ==> '(a 1 #t) (c-find '(OP ...) L) → item or '#f Searches the list for the first item that passes the predicate operation (i.e. the predicate yields a non-{{'#f}} value), then yields that item. Yields {{'#f}} if no item passes the predicate. Analogous to {{find}} from SRFI-1. (ck () (c-quote (c-find '(c-pair?) '(a (b . c) 1 (d e) #t)))) ;; ==> '(b . c) (c-find-tail '(OP ...) L) → pair or '#f Searches the list for the first item that passes the predicate operation (i.e. the predicate yields a non-{{'#f}} value), then yields the tail of the list starting with that item. Yields {{'#f}} if no item passes the predicate. Analogous to {{find-tail}} from SRFI-1. (ck () (c-quote (c-find-tail '(c-pair?) '(a (b . c) 1 (d e) #t)))) ;; ==> '((b . c) 1 (d e) #t) (c-member X L) → '#t or '#f (c-member X L '(OP ...)) → '#t or '#f Searches the list for the first occurance of {{X}}, then yields the tail of the list starting with that item. Yields {{'#f}} if the list does not contain {{X}}. Uses {{'(OP ...)}} for comparison, or {{'(c-sym-equal?)}} if the operation is omitted. So by default, {{X}} must be a symbol, list, pair, vector, or nested combination of those things. Same as {{(c-find-tail '(OP ... X) L)}}. Roughly analogous to {{member}} except for the default allowed types. (ck () (c-quote (c-member 'b '(a b c)))) ;; ==> '(b c) (ck () (c-quote (c-member 'x '(a b c)))) ;; ==> '#f (ck () (c-quote (c-member '(a b c) '((a) (x y z) (a b)) '(c-u=)))) ;; ==> '((x y z) (a b)) ;; Because (c-u= '(a b c) '(x y z)) yields '#t (c-any '(OP ...) L) → result or '#f Calls the operation on each value in the given list until it finds a result that is not {{'#f}}, then yields that result. Yields {{'#f}} if the predicate yields {{'#f}} for all items in the list, or if the list is empty. Analogous to {{any}} from SRFI-1. (ck () (c-quote (c-any '(c-pair?) '()))) ;; ==> '#f (ck () (c-quote (c-any '(c-pair?) '(a b c)))) ;; ==> '#f (ck () (c-quote (c-any '(c-pair?) '(a (b . c))))) ;; ==> '#t (ck () (c-quote (c-any '(c-cons 'z) '(a b c)))) ;; ==> '(1 . a) ;; Because (c-cons 'z 'a) yields a value that is not '#f. (c-every '(OP ...) L) → result or '#f Calls the operation on each value in the given list until it finds a result that is {{'#f}}, then yields {{'#f}}. If the predicate yields a non-{{'#f}} value for every item in the list, this yields the result of calling the predicate on the last item. Yields {{'#t}} if the list is empty. Analogous to {{every}} from SRFI-1. (ck () (c-quote (c-every '(c-pair?) '()))) ;; ==> '#t (ck () (c-quote (c-every '(c-pair?) '(a (b . c))))) ;; ==> '#f (ck () (c-quote (c-every '(c-pair?) '((a . b) (b . c))))) ;; ==> '#t (ck () (c-quote (c-every '(c-cons 'z) '(a b c)))) ;; ==> '(z . c) ;; Because all results were non-'#f and (c-cons 'z 'c) was the final operation. (c-assoc KEY ALIST) → pair or '#f (c-assoc KEY ALIST '(OP ...)) → pair or '#f Searches {{ALIST}} for the first pair whose car matches {{KEY}}, then yields that pair. Yields {{'#f}} if no match is found. {{ALIST}} must be an association list, i.e. a list of pairs. Uses {{'(OP ...)}} for comparison, or {{'(c-sym-equal?)}} if {{'(OP ...)}} is omitted. Analogous to {{assoc}} from SRFI-1. (ck () (c-quote (c-assoc 'x '((a . 1) (b . 2) (a . 3))))) ;; ==> '#f (ck () (c-quote (c-assoc 'a '((a . 1) (b . 2) (a . 3))))) ;; ==> '(a . 1) (ck () (c-quote (c-assoc '(a) '((a . 1) (b . 2) ((a) . 3))))) ;; ==> '((a) . 3) (c-alist-delete KEY ALIST) → list (c-alist-delete KEY ALIST '(OP ...)) → list Removes all pairs in {{ALIST}} whose car matches {{KEY}}. {{ALIST}} must be an association list, i.e. a list of pairs. Uses {{'(OP ...)}} for comparison, or {{'(c-sym-equal?)}} if {{'(OP ...)}} is omitted. Analogous to {{alist-delete}} from SRFI-1. Based on {{c-delete-assoc}} from the original implementation. (ck () (c-quote (c-alist-delete 'a '((a . 1) (b . 2) (a . 3) (c . 4))))) ;; ==> '((b . 2) (c . 4) (ck () (c-quote (c-alist-delete '(a) '((a . 1) (b . 2) ((a) . 3))))) ;; ==> '((a . 1) (b . 2)) ==== Vector Processing (c-vector X ...) → vector Yields a vector containing the given items. Analogous to {{vector}}. (c-list->vector L) → vector Yields a vector containing the same items as the given list. Analogous to {{list->vector}} from SRFI-43. (c-vector->list V) → list Yields a list containing the same items as the given vector. Analogous to {{vector->list}} from SRFI-43. (c-vector-reverse V) → vector Yields the given vector in reverse order. Similar to {{vector-reverse-copy}} from SRFI-43, but does not take a start or end argument. (c-vector-suffix V X ...) → vector Yields the given vector with the extra arguments added to the end. (ck () (c-quote (c-vector-suffix '#(a b) 'c 'd))) ;; ==> '#(a b c d) (c-vector-append V ...) → vector Appends the given vectors. Analogous to {{vector-append}} from SRFI-43, but only accepts two vectors. (ck () (c-quote (c-vector-append))) ;; ==> '#() (ck () (c-quote (c-vector-append '#(a b) '#(c d) '#(e f)))) ;; ==> '#(a b c d e f) (c-vector-map '(OP ...) V) → vector Yields a vector by calling the quoted operation on each item in the given vector. The operation may have leading arguments. Analogous to {{vector-map}} from SRFI-43, but only accepts one vector. ==== Unary Math The CK-macros in this section perform mathematical operations by treating lists as unary numbers. Unary math is pretty slow for large values or complex operations, but it is interesting, portable, and maybe even useful in some cases. Unary numbers are a way of representing non-negative integers as a list of a certain length. For example, the list {{'(a b c d e)}} means the number 5, and the list {{'()}} means the number 0. The contents of the list do not matter, only the length. Negative numbers and non-integral numbers cannot be represented in unary. (c-u= U1 U2) → '#t or '#f Unary equality. Yields {{'#t}} if the two lists have the same lengths, otherwise yields {{'#f}}. (ck () (c-quote (c-u= '(a b c) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u= '(1 2 3) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u= '(1 2) '(a b c)))) ;; ==> '#f (c-u< U1 U2) → '#t or '#f Unary less-than. Yields {{'#t}} if the first list is shorter than the second list, otherwise yields {{'#f}}. (ck () (c-quote (c-u< '(1 2) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u< '(1 2 3) '(a b c)))) ;; ==> '#f (c-u<= U1 U2) → '#t or '#f Unary less-than-or-equals. Yields {{'#t}} if first list is the same length or shorter than the second list, otherwise yields {{'#f}}. (ck () (c-quote (c-u<= '(1 2) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u<= '(1 2 3) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u<= '(1 2 3 4) '(a b c)))) ;; ==> '#f (c-u> U1 U2) → '#t or '#f Unary greater-than. Yields {{'#t}} if the first list is longer than the second list, otherwise yields {{'#f}}. (ck () (c-quote (c-u> '(1 2 3 4) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u> '(1 2 3) '(a b c)))) ;; ==> '#f (c-u>= U1 U2) → '#t or '#f Unary greater-than-or-equals. Yields {{'#t}} if first list is same length or longer than the second list, otherwise yields {{'#f}}. (ck () (c-quote (c-u>= '(1 2 3 4) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u>= '(1 2 3) '(a b c)))) ;; ==> '#t (ck () (c-quote (c-u>= '(1 2) '(a b c)))) ;; ==> '#f (c-uzero? U) → '#t or '#f Unary {{zero?}}. Yields {{'#t}} if the list is empty, otherwise yields {{'#f}}. Same as {{c-null?}}. (ck () (c-quote (c-uzero? '()))) ;; ==> '#t (ck () (c-quote (c-uzero? '(a)))) ;; ==> '#f (c-ueven? U) → '#t or '#f Unary {{even?}}. Yields {{'#t}} if the given list's length is even (i.e. a multiple of 2), otherwise yields {{'#f}}. (ck () (c-quote (c-ueven? '()))) ;; ==> '#t (ck () (c-quote (c-ueven? '(a)))) ;; ==> '#f (ck () (c-quote (c-ueven? '(a b)))) ;; ==> '#t (c-uodd? U) → '#t or '#f Unary {{odd?}}. Yields {{'#t}} if the given list's length is odd length (i.e. not a multiple of 2), otherwise yields {{'#f}}. (ck () (c-quote (c-uodd? '()))) ;; ==> '#f (ck () (c-quote (c-uodd? '(a)))) ;; ==> '#t (ck () (c-quote (c-uodd? '(a b)))) ;; ==> '#f (c-u+ U1 U2) → list Unary addition. Same as {{c-append}}. This was named {{c-add}} in the original implementation. (ck () (c-quote (c-u+ '(a b) '(c)))) ;; ==> '(a b c) (c-u- U1 U2) → list Unary subtraction. Drops an element from the front of the first list for each element in second list, then yields the remaining list. Negative numbers cannot be represented in unary, so this yields '() if the second list is equal or longer than the first. (ck () (c-quote (c-u- (c-list 'a 'b 'c 'd) '(x y)))) ;; ==> '(c d) (ck () (c-quote (c-u- (c-list 'a 'b) (c-list 'x 'y 'z)))) ;; ==> '() ;; Because negative numbers cannot be represented in unary. (c-u* U1 U2) → list Unary multiplication. Yields a list containing the contents of the first list, repeated once for every item in the second list. Based on {{c-mul}} from the original implementation, except the symbol 'u has no special significance, and result is made from duplicating the first list. (ck () (c-quote (c-u* '(a b) '(c d e)))) ;; ==> '(a b a b a b) (c-u/ U1 U2) → list Unary division. Yields a list of two unary numbers, representing the quotient and the remainder of the division. Given the second list has length {{N}}, the quotient will contain every {{N}}th item from the first list, and the remainder will contain the tail of the first list. Division by zero (empty list) is a syntax error. (ck () (c-quote (c-u/ '(a b c d e f g h i j k) '(x y z)))) ;; ==> '((g d a) (j k)) ;; Because 11 / 3 = 3 with a remainder of 2. (c-ufactorial U) → list Unary factorial. If the given list has length zero, yields the list {{'(u)}}. If the given list has length one, yields the given list. Otherwise, yields a list containing items of the given list repeated {{(N-1)!}} times, where {{N}} is the length of the given list. This was named {{c-fact}} in the original source. (ck () (c-quote (c-ufactorial '(a b c)))) ;; ==> '(a b c a b c) ;; Because 3! = 6. (c-udrop L U) → list Drops up to U items from the front of the given list, where U is a unary number. Same as {{c-u-}}. Analogous to {{drop}} from SRFI-1, but uses unary numbers, and yields empty list if the list is too short. (ck () (c-quote (c-udrop (c-list 'a 'b 'c 'd) '(x y)))) ;; ==> '(c d) (ck () (c-quote (c-udrop (c-list 'a 'b) (c-list 'x 'y 'z)))) ;; ==> '() (c-utake L U) → list Yields a list containing up to U items from the front of the given list, where U is a unary number. Analogous to {{take}} from SRFI-1, but uses unary numbers, and yields the entire list if it is too short. (ck () (c-quote (c-utake '(a b c d) '(x y z)))) ;; ==> '(a b c) (ck () (c-quote (c-utake '(a b) '(x y z)))) ;; ==> '(a b)