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/5/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 an enhanced version of the core {{ck}} macro, many useful (and some not-so-useful) predefined CK-macros, the {{ck-wrapper}} procedure, and many wrappers of R5RS procedures. 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: Released to the public domain. See [[http://unlicense.org]] '''Table of Contents''' [[toc:]] === Version History ; 0.3.0 (2019-03-17) : Enhanced the core {{ck}} macro to support quasiquotation. Added some new portable CK-macros. Clarified license. ; 0.2.0 (2019-02-28) : Ported to CHICKEN 5. Added {{ck-wrapper}} and many R5RS wrappers. Added some new portable CK-macros. Breaking changes to {{c-apply}}. Renamed some CK-macros. ; 0.1.1 (2016-02-07) : Fixed {{c-append}} and {{c-vector-append}} failing when given one argument. ; 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-map1}} and {{c-compose}} for examples of higher-ordered macros. CK-macros are not as flexibile, powerful, or efficient as CHICKEN's [[/man/5/Module (chicken syntax)|explicit and implicit renaming macros]], but CK-macros are much more portable. * The [[#ck|core {{ck}} macro]] and everything in the [[#portable-ck-macros|Portable CK-Macros]] section are implemented using only standard R5RS features, such as {{syntax-rules}}. This means they will work on any implementation of R5RS or later. * The [[#ck-wrapper|{{ck-wrapper}} procedure]] and everything in the [[#non-portable-r5rs-wrappers|Non-portable R5RS Wrappers]] section are implemented using [[/man/5/Module (chicken syntax)#explicit-renaming-macros|{{er-macro-transformer}}]], which is not standard R5RS but is available in many Scheme implementations. === How to write CK-macros (Note: If you do not require strict R5RS portability, the easiest way to create a CK-macro is with [[#ck-wrapper|{{ck-wrapper}}]].) Here is a basic template for portable 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/lib/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 to 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 macro, like so: (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!")). === Partial application Many CK-macros, such as {{c-compare}} and {{c-map1}}, take one or more operations as an argument. This is denoted with {{'(OP ...)}} in the CK-macro's signature. For example, {{c-map1}} takes an operation which it applies to every element of the list: (ck () (c-quote (c-map1 '(c-vector) '(2 3 4)))) ;; ==> '(#(2) #(3) #(4)) ;; Equivalent to: (ck () (c-quote (c-list (c-vector '2) (c-vector '3) (c-vector '4)))) All CK-macros which take an operation allow '''partial application''', by providing initial arguments that should be used when performing the operation: (ck () (c-quote (c-map1 '(c-vector 'x 'y) '(2 3 4)))) ;; ==> '(#(x y 2) #(x y 3) #(x y 4)) ;; Equivalent to: (ck () (c-quote (c-list (c-vector 'x 'y '2) (c-vector 'x 'y '3) (c-vector 'x 'y '4)))) You can even build up complex operations by partially applying {{c-compose}} or {{c-rcompose}}, even with partially applied operations as the initial arguments! (ck () (c-quote (c-map1 '(c-rcompose '((c-* '10) (c-number->string) (c-string-append '"foo") (c-string->symbol))) '(1 2 3)))) ;; ==> '(foo10 foo20 foo30) === Quasiquotation In '''version 0.3.0 and later''', the core {{ck}} macro supports quasiquotation. Internally, {{(quasiquote x)}} (also written as {{`x}}) is converted into {{(c-quasiquote 'x)}}, a call to the {{c-quasiquote}} CK-macro, which handles unquoting. Quasiquotation can be used as the argument to the core {{ck}} macro itself, and/or in arguments to CK-macros. This is useful for assembling mostly-literal forms, lists, and vectors: (ck () `(define (foo) (list ,@(c-list '1 '2) ,(c-vector '3)))) ;; ==> (define (foo) (list 1 2 #(3))) (ck () (c-vector-reverse `#(1 ,@(c-list '2 '3)))) ;; ==> #(3 2 1) === Debugging CK-macros utilize the Scheme macro system in unusual ways, so they are sometimes more difficult to debug than typical Scheme code. The most common error message when using CK-macros is "no rule matches form". This usually indicates one of two problems: * If the error message shows a call to {{ck}}, you are probably missing a quote. * If the error message shows a call to a CK-macro like {{c-cons}}, you probably passed the wrong number or type of arguments. ==== Missing quote As explained in the section [[#how-to-write-ck-macros|How to write CK-macros]], all values must be quoted, even values which normally do not need to be quoted in Scheme code, such as strings, numbers, and booleans. For example, the code {{(ck () (c-not #t))}} will result in an error like this: Syntax error: no rule matches form (ck123 (((c-not))) #t) In the error message above, {{ck123}} is the core {{ck}} macro. The Scheme macro system has appended a unique number for macro hygiene. The number will vary, and is usually not important to pay attention to. Because this error message shows a call to {{ck}}, we know it probably indicates a missing quote. Indeed, the solution is to quote the {{#t}}, like this: {{(ck () (c-not '#t))}} Sometimes the error is not so obvious, and you need to read the stack to find clues about what the problem is and where in the code it happened. ==== Reading error messages As explained in the section [[#how-to-write-ck-macros|How to write CK-macros]], the first argument to the core {{ck}} macro is always the stack. The stack is a list of pending operations and their arguments. The first item in the stack is the most recent (inner-most) pending operation, which will be resumed once the current operation is complete. The last item in the stack is the oldest (outer-most) pending operation. You can use this like a "stack trace" to locate where in the code an error occurred. Consider the following code, which has a mistake somewhere: (ck () (x 'x1 'x2 (y (c-cons 'y1 'y2) (z 'z1 z2 'z3) 'y3 (c-list 'y4)))) When compiled, we see an error like this: Syntax error: no rule matches form (ck67 (((z (quote65 z1)) (quote z3)) ((y (quote56 (y1 . y2))) (quote y3) (c-list (quote y4))) ((x (quote30 x1) (quote33 x2)))) z2) That looks pretty scary, but it's easier to understand if we reformat it a little: (ck (((z 'z1) 'z3) ((y '(y1 . y2)) 'y3 (c-list 'y4)) ((x 'x1 'x2))) z2) The first place to look is at the bottom, the last argument to {{ck}}. That is the expression which is currently being evaluated, and therefore is the immediate cause of the error: we forgot to quote {{z2}}. In this case, we only use the expression {{z2}} in one place, so it is easy to locate exactly where the problem is in our code. But it's not always possible to tell where the error occurred just by looking at what argument is currently being evaluated. Sometimes you need to look at the stack, which is the first argument to {{ck}}. In this example we know that the error occurred while evaluating arguments to {{z}}, because that is at the top of the stack. We know the value {{'z1}} has already been evaluated because it is inside the list with {{z}}. The expression {{'z3}} is outside the list, still waiting to be evaluated, after we finish evaluating the current argument. Moving down one level of the stack, we can see that before calling {{z}}, we were evaluating arguments to {{y}}. The value {{'(y1 . y2)}} is inside the list with {{y}}, so we know it has already been evaluated; it came from the expression {{(c-cons 'y1 'y2)}}. The expressions {{'y3}} and {{(c-list 'y4)}} are outside the list, waiting to be evaluated after we finish evaluating the call to {{z}}. And moving one more level down the stack, we were evaluating arguments to {{x}}. The values {{'x1}} and {{'x2}} have already been evaluated, and there are no expressions waiting to be evaluated. The final argument in our call to {{x}} would be the result of the call to {{y}}, which is currently in the process of being evaluated. ==== Errors inside CK-macro calls Sometimes a "no rule matches form" error will occur while evaluating a call to some CK-macro like {{c-cons}}, not a call to the core {{ck}} macro. This often indicates that the wrong number or type of arguments were passed to the CK-macro: (ck () (c-quote (c-list '1 (c-cons '2 '3 '4) '5))) Syntax error: no rule matches form (c-cons (((c-list (quote36 1)) (quote 5)) ((c-quote))) (quote45 2) (quote48 3) (quote51 4)) Notice that the error shows a call to {{c-cons}}, not {{ck}} like it did in the examples above. That indicates that each of the arguments to {{c-cons}} was evaluated with no errors, but there is some problem with the call to {{c-cons}} itself. Like before, we can reformat the error output to make it easier to understand: (c-cons (((c-list '1) '5) ((c-quote))) '2 '3 '4) We can see that the error occurred while evaluating a call to {{c-cons}} with three arguments: {{'2}}, {{'3}}, and {{'4}}. The problem is that we passed too many arguments to {{c-cons}}. Also, because the first argument to every CK-macro is the stack, we can read the stack to see where in the code the error happened. We can see that, before we started evaluating {{c-cons}}, we were evaluating arguments to {{c-list}}. And before that, we were evaluating {{c-quote}}. The error can also occur if you pass the wrong type of argument: (ck () (c-quote (c-vector->list '(1 2 3)))) Syntax error: no rule matches form (c-vector->list (((c-quote))) (quote36 (1 2 3))) In this example, {{c-vector->list}} expects to be passed a vector, but we passed it a list. === Known issues and limitations ==== Slow compilation CK-macros are pretty slow to compile, because the computation is done at compile time, using ''very'' deeply recursive macro expansions. Non-portable wrappers created with [[#ck-wrapper|{{ck-wrapper}}]] are probably somewhat faster than the portable CK-macros created with {{syntax-rules}}. But this library prioritizes portability over efficiency, so CK-macros are only implemented as wrappers if it is ''impossible'' to implement them using {{syntax-rules}}. You could likely improve compilation speed in your own code by redefining various CK-macros using {{ck-wrapper}}. ==== Pitfalls of c-sym-eq? {{c-sym-eq?}} has some strange and unexpected behaviors because of the way it uses {{let-syntax}}. * The behavior of {{c-sym-eq?}} is undefined and non-portable when comparing anything except symbols. * You should not use {{c-sym-eq?}} in any code that expands into a definition (of a variable, procedure, etc.), because that definition will not be visible from outside. This is because definitions that occur within the body of {{let-syntax}} are internal definitions, not global definitions. For example, this code will not work as expected: (ck () (c-list 'define 'x (c-sym-eq? 'a 'a))) You might expect it to expand to {{(define x #t)}}, defining a global variable {{x}} with the value {{#t}}. But even though {{c-sym-eq?}} seems to be used "inside" the definition, the core {{ck}} macro turns things "inside out" to eagerly expand macro arguments first. So, the definition will actually appear inside of a {{let-syntax}}, and {{x}} will not be visible from outside. These pitfalls also affect other macros that use {{c-sym-eq?}} directly or indirectly: * {{c-sym-equal?}} * {{c-member}} with the default comparison operator * {{c-assoc}} with the default comparison operator * {{c-alist-delete}} with the default comparison operator It is believed to be impossible to fix {{c-sym-eq?}} in a portable way, so it is recommended that you avoid using it or {{c-sym-equal?}} if possible. If you do not require strict R5RS portability, you should use the non-portable wrappers {{c-eq?}} and {{c-equal?}} instead. === ck (ck s 'VAL) (ck s `VAL) (ck s (OP ...)) This is the core {{ck}} macro, which implements the CK abstract machine. In '''version 0.3.0 and later''', this macro has been enhanced to support [[#quasiquotation|quasiquotation]]. This macro's public interface has three shapes: with a quoted value, with a quasiquoted value, and 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)))}}. ; 'VAL : 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. ; `VAL : A [[#quasiquotation|quasiquoted]] value. This is syntactic sugar for {{(c-quasiquote 'VAL)}}. ; (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))}}. === ck-wrapper (ck-wrapper proc) → macro transformer Wrap a procedure in a CK-macro, returning a macro transformer that can be used with {{define-syntax}} or {{let-syntax}}. {{ck-wrapper}} requires '''version 0.2.0 or later''' of the ck-macros egg. It is considered '''non-portable''' because it depends on [[/man/5/Module (chicken syntax)#explicit-renaming-macros|{{er-macro-transformer}}]], which is not defined in standard R5RS. However, it should work on any Scheme which defines {{er-macro-transformer}} in the usual way. You can wrap any other expression that evaluates to a procedure, such as a procedure name, a lambda form, a "let over lambda" expression, etc. The expression will be evaluated once, when the call to {{ck-wrapper}} is evaluated. Therefore, the procedure you are wrapping must be available in the syntax environment at macro expansion time. (In other words, you should use [[/man/5/Module (chicken syntax)#define-for-syntax|{{define-for-syntax}}]], [[/man/5/Modules#import-for-syntax|{{import-for-syntax}}]], etc.) Examples: ;;; Import iota from SRFI 1. (cond-expand (chicken-4 (use-for-syntax (only srfi-1 iota))) (chicken-5 (import-for-syntax (only (srfi 1) iota)))) (define-syntax c-iota (ck-wrapper iota)) (ck () (c-quote (c-iota '5))) ;; ==> '(0 1 2 3 4) ;;; A helper procedure that returns a closure. (define-for-syntax (make-adder n) (lambda (x) (+ x n))) ;;; Temporarily define a ck-wrapper around a closure. (let-syntax ((c-add2 (ck-wrapper (make-adder 2)))) ;; Map c-add2 over the result of c-iota. (ck () (c-quote (c-map1 '(c-add2) (c-iota '5))))) ;; ==> '(2 3 4 5 6) === 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-quasiquote X) → result Implements [[#quasiquotation|quasiquotation]]. Added in '''version 0.3.0'''. The core {{ck}} macro has special support for converting {{(quasiquote x)}} (also written as {{`x}}) into {{(c-quasiquote 'x)}}. Within a call to {{c-quasiquote}}, you can use {{(unquote y)}} (also written as {{,y}}) and {{(unquote-splicing z)}} (also written as {{,@z}}). They are supported inside vectors as well as inside pairs/lists. ;; These expressions are exactly equivalent: (ck () `(define (foo) (list ,@(c-list '1 '2) ,(c-vector '3)))) (ck () (c-quasiquote '(define (foo) (list ,@(c-list '1 '2) ,(c-vector '3))))) ;; ==> (define (foo) (list 1 2 #(3))) (ck () `#(1 ,@(c-list '2 '3))) (ck () (c-quasiquote '#(1 ,@(c-list '2 '3)))) ;; ==> #(1 2 3) (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. '''Prior to version 0.2.0''', the arguments in the final list required an extra level of quoting. Analogous to {{apply}}. (ck () (c-quote (c-apply '(c-list) 'a '(b) '(c d)))) ;; ==> '(a (b) c d) (c-compose '((OP-N ...) ... (OP-1 ...)) X ...) → result Compose one or more CK-macros and apply them to the arguments. Calls the right-most {{OP}} with the arguments {{X ...}}, then calls the next-right-most {{OP}} with that result, and so on: (OP-N ... (OP-2 ... (OP-1 ... X ...))) {{OP-1}} must accept all the {{X}}s as arguments, and the other {{OP}}s must each accept one argument (the result of the previous operation). See also {{c-rcompose}}, which is more efficient. Added in '''version 0.2.0''' (ck () (c-compose '((c-car) (c-cdr)) '(1 2 3))) ;; ==> 2 ;;; Map over a list of lists to see which are not empty. (ck () (c-quote (c-map1 '(c-compose '((c-not) (c-null?))) '((1) () (2 3))))) ;; ==> '(#t #f #t) (c-rcompose '((OP-1 ...) ... (OP-N ...)) X ...) → result Like {{c-compose}}, but the operations are called in the reverse order (left to right). This is more efficient than {{c-compose}}. Added in '''version 0.2.0''' (c-flip '(OP ...) X Y) → (OP ... Y X) Calls the operation with the two extra arguments in reverse order. Added in '''version 0.3.0'''. (c-branch '((OP ...) ...) X ...) → '(result ...) Yields a list of the results of calling each operation with the {{X}}s. Added in '''version 0.3.0'''. (ck () (c-quote (c-branch '((c-list) (c-cons) (c-* '10)) '3 '5))) ;; '((3 5) ;; (3 . 5) ;; 150) (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 (c-constantly X Y ...) → X Always yields {{X}}, regardless of the other arguments. May be useful for some higher-order macros. Added in '''version 0.3.0'''. ==== CK-macro builders (c-make-rules '(L ...) '(P X) ...) → '(syntax-rules ...) Build a CK-macro based on syntax-rules. Added in '''version 0.3.0'''. Given a list of zero or more literal symbols, and one or more pattern/expression lists, yields a syntax-rules form for a CK-macro with the following behavior: * Given argument(s) that match any pattern {{P}}, yields the value of the associated expression {{X}}, which may use identifiers from {{P}}. Fails if no pattern matches. Each pattern {{P}} is a list of zero or more sub-patterns, which will be matched (as with syntax-rules) against the already-evaluated and quoted arguments given to the new CK-macro. Alternatively, {{P}} may be an identifier which will capture all arguments as a list. Each expression {{X}} is a single CK-macro expression or quoted value. Identifiers from the pattern can be used in the expression, as with syntax-rules. Symbols in the literals list {{(L ...)}} will be treated as literal identifiers in patterns. Additionally, {{quote}} is always treated as a literal identifier. Caveats: * Using {{...}} in a pattern or expression may not work portably with all Scheme systems. * Symbols begining with {{%ck:}} are reserved for internal use and must not appear in any {{L}}, {{P}}, or {{X}}. (ck () `(define-syntax c-flip-flop ,(c-make-rules '(flip flop) '(('flip 'x 'y) (c-list 'y 'x)) '(('flop 'x 'y) '#f)))) ;; The above is basically equivalent to: ;; (define-syntax c-flip-flop ;; (syntax-rules (flip flop quote) ;; ((_ s 'flip 'x 'y) ;; (ck s (c-list 'y 'x))) ;; ((_ s 'flop 'x 'y) ;; (ck s '#f)))) (ck () (c-quote (c-flip-flop 'flip '1 '2))) ;; ==> '(1 2) (ck () (c-quote (c-flip-flop 'flop '1 '2))) ;; ==> #f (c-make-next '(X1 X2 ...)) → '(syntax-rules ...) Build a CK-macro that yields the next item in a sequence. Added in '''version 0.3.0'''. Given a list of unique items, yields a syntax-rules form for a CK-macro with the following behavior: * Given an item in the list, yields the item following it. Yields {{'#f}} if given the final item or an item not in the list. E.g. with a list of increasing integers, the CK-macro behaves like {{c-dadd1}}. With a list of decreasing integers, it behaves like {{c-dsub1}}. The list must have at least two items, with no duplicates. The items should be literal constants: booleans, numbers, strings, characters; or (possibly nested) pairs, lists, or vectors of those things. Symbols are allowed but the result may not be what you expect because they are treated as identifiers in the patterns. Be advised that compilation can be very slow if there are many items because it generates a syntax-rules with many branches. (ck () `(define-syntax c-next-square ,(c-make-next '(0 1 4 9 16)))) ;; The above is basically equivalent to: ;; (define-syntax c-next-square ;; (syntax-rules (quote) ;; ((_ s '0) (ck s '1)) ;; ((_ s '1) (ck s '4)) ;; ((_ s '4) (ck s '9)) ;; ((_ s '9) (ck s '16)) ;; ((_ s otherwise) (ck s '#f)))) (ck () (c-next-square '4)) ;; ==> '9 (ck () (c-next-square '16)) ;; ==> '#f ==== Boolean Logic (c-not X) → '#t or '#f Yields {{'#t}} if the argument is {{'#f}}, otherwise yields {{'#f}}. Analogous to {{not}}. (c-true X ...) → '#t Always yields {{'#t}}, regardless of its arguments. May be useful for some higher-order macros. Equivalent to {{(c-constantly '#t X ...)}}. Added in '''version 0.2.0'''. ;;; Recursively check if two structure have the same length, ;;; nesting, etc, while ignoring the value of the atoms. (ck () (c-compare? '(c-true) '(1 #(2) 3) '(a #(b) c))) ;; ==> '#t (c-false X ...) → '#f Always yields {{'#f}}, regardless of its arguments. May be useful for some higher-order macros. Equivalent to {{(c-constantly '#f X ...)}}. Added in '''version 0.2.0'''. (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 '''ATTENTION:''' This CK-macro has [[#pitfalls-of-c-sym-eq|major pitfalls]] that you should be aware of. If you do not require strict R5RS portability, it is recommended to use {{c-eq?}} instead. 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 '''ATTENTION:''' This CK-macro has [[#pitfalls-of-c-sym-eq|major pitfalls]] that you should be aware of. If you do not require strict R5RS portability, it is recommended to use {{c-equal?}} instead. 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. (c-compare? '(OP ...) X Y) → '#t or '#f Recursively compares atoms, pairs, lists, or vectors, using {{OP}} as the predicate to compare atoms. Similar to {{equal?}} but with a custom predicate. Added in '''version 0.2.0'''. {{OP}} will be called with two arguments: an atom of {{X}}, and the corresponding atom of {{Y}}. In other words, the Nth atom of {{X}} will be compared with the Nth atom of {{Y}}, descending recursively into nested structures. If {{X}} and {{Y}} are themselves atoms, they are compared directly with {{OP}}. Yields {{'#f}} if {{X}} and {{Y}} have dissimilar structures (length, nesting, type), or if {{OP}} yields {{'#f}} for any corresponding atoms of {{X}} and {{Y}}. Otherwise yields {{'#t}}. (ck () (c-compare? '(c-string-ci=?) '#("a" ("b")) '#("A" ("B")))) ;; ==> #t ;;; X is a vector with a list, but Y is a list with a vector. ;;; The structures are dissimilar. (ck () (c-compare? '(c-string-ci=?) '#("a" ("b")) '("a" #("b")))) ;; ==> #f ;;; Can use any predicate. Here, X and Y have same structure, ;;; and each atom of X is less than the correponding atom of Y. (ck () (c-compare? '(c-<) '(1 #(5)) '(2 #(6)))) ;; ==> #t ;;; Can compare atoms directly. (ck () (c-compare? '(c-<) '1 '2)) ;; ==> #t ==== List Processing (c-cons X Y) → '(X . Y) Yields a pair with the two given arguments. Analogous to {{cons}}. (ck () (c-quote (c-cons 'a 'b))) ;; ==> '(a . b) (ck () (c-quote (c-cons '+ '(1 2)))) ;; ==> '(+ 1 2) (ck () (c-quote (c-cons '+ (c-cons '1 (c-cons '2 '()))))) ;; ==> '(+ 1 2) (c-cons* X ... Y Z) → '(X ... Y . Z) Yields a list from consing all the arguments together in a chain. If the final argument Z is a list, the result will be a proper list. Otherwise it will be a "dotted list". Analogous to {{cons*}} from SRFI 1. Added in '''version 0.3.0'''. (ck () (c-quote (c-cons* 'a 'b 'c 'd))) ;; ==> '(a b c . d) (ck () (c-quote (c-cons* 'a 'b 'c '(d)))) ;; ==> '(a b c d) (c-xcons X Y) → '(Y . X) Like {{c-cons}}, but exchanges the order of arguments. Analogous to {{xcons}} from SRFI 1. Added in '''version 0.2.0'''. (ck () (c-quote (c-xcons 'a 'b))) ;; ==> '(b . a) (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-prefix L X ...) → list Yields the given list with the extra arguments added to the front. Added in '''version 0.3.0'''. (ck () (c-quote (c-prefix '(c d) 'a 'b))) ;; ==> '(a b c d) (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 'd))) ;; ==> '(a b c d) (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-map1 '(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. Analogous to {{append-map}} from SFRI-1, but only accepts one list. '''Prior to version 0.2.0''', this was named {{c-append-map}}. This was named {{c-concatMap}} in the original implementation. (ck () (c-quote (c-append-map1 '(c-list 'a 'b) '(1 2)))) ;; ==> '(a b 1 a b 2) (c-map1 '(OP ...) L) → list Yields a list by calling the quoted operation on each item in the given list. Analogous to {{map}}, but only accepts one list. (See also {{c-map2}} ... {{c-map5}} for versions that accept more lists.) '''Prior to version 0.2.0''', this was named {{c-map}}. (ck () (c-quote (c-map1 '(c-cons 'a) '(1 2)))) ;; ==> '((a . 1) (a . 2)) (c-map2 '(OP ...) L1 L2) → list (c-map3 '(OP ...) L1 L2 L3) → list (c-map4 '(OP ...) L1 L2 L3 L4) → list (c-map5 '(OP ...) L1 L2 L3 L4 L5) → list Like {{c-map1}}, but they accept exactly two, three, four, or five lists respectively. {{OP}} must accept two, three, four, or five extra arguments. If the lists are different lengths, terminates when the shortest list runs out. Analogous to {{map}} from SRFI 1, but they accept a specific number of lists. Added in '''version 0.2.0'''. ;; The argument '(1 2) is shortest so the result only has two items. (ck () (c-quote (c-map3 '(c-list) '(a b c) '(1 2) '(x y z)))) ;; ==> '((a 1 x) (b 2 y)) (c-fold1 '(OP ...) INIT L) → result Yield a value by repeatedly calling the quoted operation with each item from the list and 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. '''Prior to version 0.2.0''', this was named {{c-fold}}. (ck () (c-quote (c-fold1 '(c-cons) '(x) '()))) ;; ==> '(x) (ck () (c-quote (c-fold1 '(c-cons) '(x) '(a b c d e f)))) ;; ==> '(f e d c b a x) (c-unfold '(P ...) '(F ...) '(G ...) SEED) → list (c-unfold '(P ...) '(F ...) '(G ...) SEED '(TAIL-GEN ...)) → list Generate a list by recursively "unfolding" from a seed. Analogous to {{unfold}} from SRFI 1. Added in '''version 0.3.0'''. Takes several operations which are called with the seed: * {{(P ... SEED)}} should yield non-{{'#f}} if it is time to stop generating. * {{(F ... SEED)}} should yield an item to be appended to the list. * {{(G ... SEED)}} should yield the next {{SEED}}. * {{(TAIL-GEN ... SEED)}} should yield the tail of the list. Called with the final {{SEED}} after {{P}} yields non-{{'#f}}. If omitted, {{'(TAIL-GEN ...)}} defaults to {{'(c-constantly '())}}. (ck () (c-quote (c-unfold '(c-> '1) ; P '(c-identity) ; F '(c-dsub1) ; G '10 ; SEED '(c-constantly '(BLASTOFF!))))) ; TAIL-GEN ;; ==> '(10 9 8 7 6 5 4 3 2 1 BLASTOFF!) (c-filter '(OP ...) L) → list Yields a list by calling the predicate operation on each item in the 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 '''ATTENTION:''' When using the default comparison operator, this CK-macro has [[#pitfalls-of-c-sym-eq|major pitfalls]] that you should be aware of. If you do not require strict R5RS portability, it is recommended to use the comparison operator {{'(c-equal?)}} instead. 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-any1 '(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, but only accepts one list. '''Prior to version 0.2.0''', this was named {{c-any}}. (ck () (c-quote (c-any1 '(c-pair?) '()))) ;; ==> '#f (ck () (c-quote (c-any1 '(c-pair?) '(a b c)))) ;; ==> '#f (ck () (c-quote (c-any1 '(c-pair?) '(a (b . c))))) ;; ==> '#t (ck () (c-quote (c-any1 '(c-cons 'z) '(a b c)))) ;; ==> '(1 . a) ;; Because (c-cons 'z 'a) yields a value that is not '#f. (c-every1 '(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, but only accepts one list. '''Prior to version 0.2.0''', this was named {{c-every}}. (ck () (c-quote (c-every1 '(c-pair?) '()))) ;; ==> '#t (ck () (c-quote (c-every1 '(c-pair?) '(a (b . c))))) ;; ==> '#f (ck () (c-quote (c-every1 '(c-pair?) '((a . b) (b . c))))) ;; ==> '#t (ck () (c-quote (c-every1 '(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 '''ATTENTION:''' When using the default comparison operator, this CK-macro has [[#pitfalls-of-c-sym-eq|major pitfalls]] that you should be aware of. If you do not require strict R5RS portability, it is recommended to use the comparison operator {{'(c-equal?)}} instead. 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 '''ATTENTION:''' When using the default comparison operator, this CK-macro has [[#pitfalls-of-c-sym-eq|major pitfalls]] that you should be aware of. If you do not require strict R5RS portability, it is recommended to use the comparison operator {{'(c-equal?)}} instead. 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-prefix V X ...) → list Yields the given vector with the extra arguments added to the front. Added in '''version 0.3.0'''. (ck () (c-quote (c-vector-prefix '#(c d) 'a 'b))) ;; ==> '#(a b c d) (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-map1 '(OP ...) V) → vector Yields a vector by calling the quoted operation on each item in the given vector. Analogous to {{vector-map}} from SRFI 43, but only accepts one vector. '''Prior to version 0.2.0''', this was named {{c-vector-map}}. ==== 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 (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 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 implementation. (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 the 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) ==== Decimal Integers (c-dadd1 N) → 'N+1 or '#f Add 1 to a decimal integer. If 0 <= N <= 15, yields N + 1. Otherwise yields {{'#f}}. Added in '''version 0.3.0'''. (ck () (c-dadd1 '0)) ;; ==> '1 (ck () (c-dadd1 '15)) ;; ==> '16 (ck () (c-dadd1 '16)) ;; ==> '#f The default domain is small because library compilation time increases rapidly the larger the domain is, because it generates a syntax-rules with many branches. You can define an {{add1}} with a larger (or just different) domain using {{c-make-next}} and a list of ''increasing'' integers: (ck () `(define-syntax c-my-add1 ,(c-make-next '(-5 -4 -3 -2 -1 0 1 2 3 4 5)))) (c-dsub1 N) → 'N-1 or '#f Subtract 1 from a decimal integer. If 1 <= N <= 16, yields N - 1. Otherwise yields {{'#f}}. See the notes for {{c-dadd1}}. (ck () (c-dsub1 '16)) ;; ==> '15 (ck () (c-dsub1 '1)) ;; ==> '0 (ck () (c-dsub1 '0)) ;; ==> '#f As with {{c-dadd1}}, you can define a {{sub1}} with a larger (or just different) domain using {{c-make-next}} and a list of ''decreasing'' integers: (ck () `(define-syntax c-my-sub1 ,(c-make-next '(5 4 3 2 1 0 -1 -2 -3 -4 -5)))) (c-du N) → list or '#f (c-du N '(SUB1 ...)) → list or '#f Convert from decimal integers to [[#unary-math|unary integers]]. If N is in the domain of {{SUB1}}, yields a list of that many elements, specifically the integers {{(N-1, ..., 0)}}. Otherwise, yields {{'#f}}. {{SUB1}} is any operation that given N yields N-1, where 1 <= N. Defaults to {{c-dsub1}}, which supports 1 <= N <= 16. See the note for {{c-dsub1}} for how to make an operation with a larger domain. (ck () (c-quote (c-du '0))) ;; ==> '() (ck () (c-quote (c-du '16))) ;; ==> '(15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0) (ck () (c-quote (c-du '17))) ;; ==> '#f (c-ud U) → integer or '#f (c-ud U '(ADD1 ...)) → integer or '#f Convert from [[#unary-math|unary integers]] to decimal integers. Given a list of items, yields the list's length as a decimal integer. The contents of the list do not matter, only its length. If the list length is too large for {{ADD1}}, yields {{'#f}}. {{ADD1}} is any operation that given N yields N+1, where 0 <= N. Defaults to {{c-dadd1}}, which supports 0 <= N <= 15. See the note for {{c-dadd1}} for how to make an operation with a larger domain. (ck () (c-ud '())) ;; ==> '0 (ck () (c-ud '(a b c d e f g h i j k l m n o p))) ;; ==> '16 (ck () (c-ud '(a b c d e f g h i j k l m n o p q))) ;; ==> '#f === Non-portable R5RS Wrappers These are CK-macros that wrap some R5RS procedures that are useful for building macros. Not every R5RS procedure is provided here. If you need other procedures, use [[#ck-wrapper|{{ck-wrapper}}]] to create your own wrappers. These wrappers are considered non-portable because they use ck-wrapper, which is not portable to all R5RS Scheme implementations. See the ck-wrapper docs for portability information. Some R5RS procedures have portable, non-wrapper CK-macro equivalents, which are described in the [[#portable-ck-macros|Portable CK-macros]] section, above. For example, there is no wrapper for {{pair?}} listed below, because {{c-pair?}} is a portable CK-macro listed above. ==== General (R5RS Wrappers) (c-eqv? X Y) → '#t or '#f CK-macro wrapper for {{eqv?}}. Added in '''version 0.2.0'''. (c-eq? X Y) → '#t or '#f CK-macro wrapper for {{eq?}}. Added in '''version 0.2.0'''. (c-equal? X Y) → '#t or '#f CK-macro wrapper for {{equal?}}. Added in '''version 0.2.0'''. ==== Numbers and Math (R5RS Wrappers) (c-number? X) → '#t or '#f CK-macro wrapper for {{number?}}. Added in '''version 0.2.0'''. (c-integer? X) → '#t or '#f CK-macro wrapper for {{integer?}}. Added in '''version 0.2.0'''. (c-= N ...) → '#t or '#f CK-macro wrapper for {{=}} (equal). Added in '''version 0.2.0'''. (c-< N ...) → '#t or '#f CK-macro wrapper for {{<}} (less than). Added in '''version 0.2.0'''. (c-> N ...) → '#t or '#f CK-macro wrapper for {{>}} (greater than). Added in '''version 0.2.0'''. (c-<= N ...) → '#t or '#f CK-macro wrapper for {{<=}} (less than or equal). Added in '''version 0.2.0'''. (c->= N ...) → '#t or '#f CK-macro wrapper for {{>=}} (greater than or equal). Added in '''version 0.2.0'''. (c-max N ...) → number CK-macro wrapper for {{max}}. Added in '''version 0.2.0'''. (c-min N ...) → number CK-macro wrapper for {{min}}. Added in '''version 0.2.0'''. (c-+ N ...) → number CK-macro wrapper for {{+}} (addition). Added in '''version 0.2.0'''. (c-* N ...) → number CK-macro wrapper for {{*}} (multiplication). Added in '''version 0.2.0'''. (c-- N ...) → number CK-macro wrapper for {{-}} (subtraction). Added in '''version 0.2.0'''. (c-/ N ...) → number CK-macro wrapper for {{/}} (division). Added in '''version 0.2.0'''. (c-remainder N1 N2) → number CK-macro wrapper for {{remainder}}. Added in '''version 0.2.0'''. (c-floor N) → number CK-macro wrapper for {{floor}}. Added in '''version 0.2.0'''. (c-round N) → number CK-macro wrapper for {{round}}. Added in '''version 0.2.0'''. (c-exact->inexact N) → inexact number CK-macro wrapper for {{exact->inexact}}. Added in '''version 0.2.0'''. (c-inexact->exact N) → exact number CK-macro wrapper for {{inexact->exact}}. Added in '''version 0.2.0'''. (c-number->string N) → string (c-number->string N RADIX) → string CK-macro wrapper for {{number->string}}. Added in '''version 0.2.0'''. (c-string->number STR) → number or '#f (c-string->number STR RADIX) → number or '#f CK-macro wrapper for {{string->number}}. Added in '''version 0.2.0'''. ==== Pairs and Lists (R5RS Wrappers) (c-length L) → integer CK-macro wrapper for {{length}}. Added in '''version 0.2.0'''. (c-list-ref L I) → item CK-macro wrapper for {{list-ref}}. Added in '''version 0.2.0'''. ==== Symbols (R5RS Wrappers) (c-symbol? X) → '#t or '#f CK-macro wrapper for {{symbol?}}. Added in '''version 0.2.0'''. (c-symbol->string SYM) → string CK-macro wrapper for {{symbol->string}}. Added in '''version 0.2.0'''. (c-string->symbol STR) → symbol CK-macro wrapper for {{string->symbol}}. Added in '''version 0.2.0'''. ==== Chars and Strings (R5RS Wrappers) (c-char? CHAR ...) → '#t or '#f CK-macro wrapper for {{char?}}. Added in '''version 0.2.0'''. (c-char=? CHAR ...) → '#t or '#f CK-macro wrapper for {{char=?}}. Added in '''version 0.2.0'''. (c-string? X) → '#t or '#f CK-macro wrapper for {{string?}}. Added in '''version 0.2.0'''. (c-string CHAR ...) → string CK-macro wrapper for {{string}}. Added in '''version 0.2.0'''. (c-string-length STR) → integer CK-macro wrapper for {{string-length}}. Added in '''version 0.2.0'''. (c-string-ref STR I) → char CK-macro wrapper for {{string-ref}}. Added in '''version 0.2.0'''. (c-string=? STR ...) → '#t or '#f CK-macro wrapper for {{string=?}}. Added in '''version 0.2.0'''. (c-string-ci=? STR ...) → '#t or '#f CK-macro wrapper for {{string-ci=?}}. Added in '''version 0.2.0'''. (c-substring STR START) → string (c-substring STR START END) → string CK-macro wrapper for {{substring}}. Added in '''version 0.2.0'''. (c-string-append STR ...) → string CK-macro wrapper for {{string-append}}. Added in '''version 0.2.0'''. ==== Vectors (R5RS Wrappers) (c-vector-length V) → integer CK-macro wrapper for {{vector-length}}. Added in '''version 0.2.0'''. (c-vector-ref V I) → item CK-macro wrapper for {{vector-ref}}. Added in '''version 0.2.0'''.