Using `non-fixed' sequence argument processing concept of SRFI-51, we can simulate named optional argument making use of keyword object. The following is an example: (define depth 15) (define key-check (check-lambda (a b #(c 11) ; positional optional variable #((width d) 22) ; named optional variable #((depth e) 33)) ; named optional variable (list a b c `(width ,d) `(depth ,e)))) (key-check 1) => error (key-check 1 2) => (1 2 11 (width 22) (depth 33)) (key-check 2 1) => (2 1 11 (width 22) (depth 33)) (key-check 1 2 3) => (1 2 3 (width 22) (depth 33)) (key-check 1 2 3 #(depth 10)) => (1 2 3 (width 22) (depth 10)) (key-check 1 2 3 #(depth 10) #(width 5)) => (1 2 3 (width 5) (depth 10)) (key-check 1 2 3 `#(depth ,depth) #(width 5)) => (1 2 3 (width 5) (depth 15)) (key-check 1 2 3 4 5) => error The above can be expanded as follows: (define test-check (check-lambda* ((a (number? a)) (b (number? b) (< a b)) #(c 11 (number? c) (< b c)) #((width d) 22 (number? d) (< c d)) #((depth e) 33 (number? e) (< d e)) . f) (list a b c `(width ,d) `(depth ,e) f))) (test-check 1) => error (test-check 1 2) => (1 2 11 (width 22) (depth 33) ()) (test-check 2 1) => error (test-check 1 2 3) => (1 2 3 (width 22) (depth 33) ()) (test-check 1 2 3 #(depth 10)) => error (test-check 1 2 3 #(depth 10) #(width 5))=> (1 2 3 (width 5) (depth 10) ()) (test-check 1 2 3 `#(depth ,depth) #(width 5)) => (1 2 3 (width 5) (depth 15) ()) (test-check 1 2 3 4 5) => (1 2 3 (width 22) (depth 33) (4 5)) I've attached a rough draft. -- Joo ChurlSoo Title LAMBDA extension Author Joo ChurlSoo Abstract This SRFI introduces COND-LAMBDA and COND-LAMBDA* that return different procedures according to the states of actual arguments passed in as well as the number of arguments, and another four macros, CHECK-LAMBDA and CHECK-LAMBDA*, FLOAT-LAMBDA and FLOAT-LAMBDA*, each of which creates a procedure that takes optional arguments and checks the states of ordinary arguments as well as optional arguments passed in. Rationale The COND-LAMBDA can reduce the clutter of procedures more precisely than CASE-LAMBDA of SRFI-16 by adding tests for the states of arguments passed in, such as type checking. The CHECK-LAMBDA and FLOAT-LAMBDA reduce not only the clutter of various error conditionals by checking actual arguments passed in but also somewhat lengthy code by combining respectively `fixed' and `non-fixed' sequence argument processing concept of SRFI-51 into a single syntax. The optional parameters that they take include not only positional fixed parameters but also named non-fixed parameters that are implemented without introducing a new data type such as keyword object. The COND-LAMBDA*, CHECK-LAMBDA*, and FLOAT-LAMBDA* are LET*-like forms corresponding to COND-LAMBDA, CHECK-LAMBDA, and FLOAT-LAMBDA. Specification The syntax is defined in the extended BNF of R5RS. (cond-lambda <clause>+) (cond-lambda* <clause>+) <clause> --> (<formals> <body>) <formals> --> (<variable spec>*) | <variable> | (<variable spec>+ . <variable>) <variable spec> --> <variable> | (<variable> <test>+) <test> --> <expression> COND-LAMBDA is an extended form of CASE-LAMBDA of SRFI-16. Like CASE-LAMBDA, it returns a procedure of the first <clause>, the <formals> of which is matched with the number of actual arguments. But if there are <test>s and any of the <test>s returns a false value, the subsequent <clause> is processed in spite of the match. If no <clause> matches, an error is signaled. Each <test> of COND-LAMBDA* sees the values of the previous <variable>s of <formals> like LET*. (check-lambda <formals> <body>) (check-lambda* <formals> <body>) <formals> --> | (<variable spec>* <positional opt spec>* <named opt spec>*) | <variable> | (<variable spec>+ <positional opt spec>* <named opt spec>* . <variable>) | (<positional opt spec>+ <named opt spec>* . <variable>) | (<named opt spec>+ . <variable>) <variable spec> --> <variable> | (<variable> <test>+) <positional opt spec> --> #(<variable> <default value> <test>*) <named opt spec> --> #((<name> <variable>) <default value> <test>*) <name> --> <symbol> <default value> --> <expression> <test> --> <expression> The <formals> is the same as that of COND-LAMBDA except optional variable that is a vector pattern. The optional variables should be placed at the end of <formals> list, but before any dotted rest variable. And positional optional variables should precede named optional variables. Unlike COND-LAMBDA, each macro can create a procedure that takes optional arguments. Optional variables are given <default value>s which are taken when optional arguments are not present in a call. Even though there are <test>s, they are not evaluated when the optional variable is bound to the <default value>. If any <test> of optional or ordinary variable returns a false value, an error is signaled. Unlike positional optional variables, named optional variables are not bound sequetially to the optional arguments passed in. They seek a vector whose elements are two and the first element is equal to <name>, sequentially from left to right. Then they are bound to the second elements of the sought vectors. If not sought, they are bound to the <default value>s. An error is signaled when any optional arguments remain after binding process. But if there is a dotted rest variable, it is bound to the remaining arguments. Each <test> of CHECK-LAMBDA* sees the values of the previous <variable>s of <formals> like LET*. (float-lambda <formals> <body>) (float-lambda* <formals> <body>) <formals> --> | (<variable spec>* <positional opt spec>* <named opt spec>*) | <variable> | (<variable spec>+ <positional opt spec>* <named opt spec>* . <variable>) | (<positional opt spec>+ <named opt spec>* . <variable>) | (<named opt spec>+ . <variable>) <variable spec> --> <variable> | (<variable> <test>+) <positional opt spec> --> #(<variable> <default value> <test>*) <named opt spec> --> #((<name> <variable>) <default value> <test>*) <name> --> <symbol> <default value> --> <expression> <test> --> <expression> This is the same as CHECK-LAMBDA except binding method. It temporarily binds an ordinary variable to each of ordinary actual arguments sequentially, until all <test>s return true values, then the ordinary variable is finally bound to the passed argument. If there are no <test>s, the first one of the remained ordinary actual arguments is regarded as passing. If any ordinary variable is not bound to any one of the ordinary actual arguments, an error is signaled. For positional optional variables, the process is the same as above except that <default value>s are bound to the corresponding optional variables instead of signaling an error if any optional argument does not pass the <test>s. For named optional variables, the process is the same as that of CHECK-LAMBDA. An error is signaled when any optional arguments remain after binding process. But if there is a dotted rest variable, it is bound to the remaining arguments. Each <test> of FLOAT-LAMBDA* sees the values of the previous <variable>s of <formals> like LET*. Examples (define cond-test (cond-lambda* ((a) a) (((a (number? a)) (b (number? b) (< a b))) (+ a b)) (((a (number? a)) (b (number? b))) (- a b)) (((a (string? a)) (b (string? b) (< (string-length a) (string-length b)))) (string-append a b)) (((a (string? a)) (b (string? b))) (string-append b a)) ((a b) (vector a b)) ((a b . c) (apply list a b c)))) (cond-test 1 2) => 3 (cond-test 2 1) => 1 (cond-test "a" "bc") => "abc" (cond-test "ab" "c") => "cab" (cond-test "a" 1) => #2("a" 1) (cond-test "a" 1 2) => ("a" 1 2) (define check (check-lambda* (a (b (number? b)) (c (number? c) (< b c)) (d (number? d)) #(e "s" (string? e)) #(f (+ b c) (number? f)) . g) (list a b c d e f g))) (check "a" 1 2 3) => ("a" 1 2 3 "s" 3 ()) (check "a" 2 1 3) => error (check "a" 1 2 3 "b") => ("a" 1 2 3 "b" 3 ()) (check "a" 1 2 3 4) => error (check "a" 1 2 3 "b" 4 5) => ("a" 1 2 3 "b" 4 (5)) (define float (float-lambda* (a (b (number? b)) (c (number? c) (< b c)) (d (number? d)) #(e "s" (string? e)) #(f (+ b c) (number? f)) . g) (list a b c d e f g))) (float "a" 1 2 3) => ("a" 1 2 3 "s" 3 ()) (float "a" 2 1 3) => ("a" 2 3 1 "s" 5 ()) (float "a" 1 2 3 "b") => ("a" 1 2 3 "b" 3 ()) (float "a" 1 2 3 4) => ("a" 1 2 3 "s" 4 ()) (float "a" 1 2 3 "b" 4 5) => ("a" 1 2 3 "b" 4 (5)) (define depth 15) (define key-check (check-lambda (a b #(c 11) #((width d) 22) #((depth e) 33)) (list a b c `(width ,d) `(depth ,e)))) (key-check 1) => error (key-check 1 2) => (1 2 11 (width 22) (depth 33)) (key-check 2 1) => (2 1 11 (width 22) (depth 33)) (key-check 1 2 3) => (1 2 3 (width 22) (depth 33)) (key-check 1 2 3 #(depth 10)) => (1 2 3 (width 22) (depth 10)) (key-check 1 2 3 #(depth 10) #(width 5)) => (1 2 3 (width 5) (depth 10)) (key-check 1 2 3 `#(depth ,depth) #(width 5)) => (1 2 3 (width 5) (depth 15)) (key-check 1 2 3 4 5) => error (define test-check (check-lambda* ((a (number? a)) (b (number? b) (< a b)) #(c 11 (number? c) (< b c)) #((width d) 22 (number? d) (< c d)) #((depth e) 33 (number? e) (< d e)) . f) (list a b c `(width ,d) `(depth ,e) f))) (test-check 1) => error (test-check 1 2) => (1 2 11 (width 22) (depth 33) ()) (test-check 2 1) => error (test-check 1 2 3) => (1 2 3 (width 22) (depth 33) ()) (test-check 1 2 3 #(depth 10)) => error (test-check 1 2 3 #(depth 10) #(width 5))=> (1 2 3 (width 5) (depth 10) ()) (test-check 1 2 3 `#(depth ,depth) #(width 5)) => (1 2 3 (width 5) (depth 15) ()) (test-check 1 2 3 4 5) => (1 2 3 (width 22) (depth 33) (4 5)) Implementation The following implementation is written in R5RS hygienic macros and requires SRFI-23 (Error reporting mechanism). (define-syntax wow-check ; wow means with-or-without (syntax-rules () ((wow-check (key n) v) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (vector-ref v 1) (error "check{float]-lambda[*]: too many arguments" v))) ((wow-check (key n) v t ...) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (let ((n (vector-ref v 1))) (if (and t ...) n (error "check{float]-lambda[*]: bad argument" n 'n 't ...))) (error "check{float]-lambda[*]: too many arguments" v))) ((wow-check n v) v) ((wow-check n v t ...) (let ((n v)) (if (and t ...) n (error "check{float]-lambda[*]: bad argument" n 'n 't ...)))))) (define-syntax wow-check-key! (syntax-rules () ((wow-check-key! z (key n) d) (let ((v (car z))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (begin (set! z (cdr z)) (vector-ref v 1)) (let lp ((head (list v)) (tail (cdr z))) (if (null? tail) d (let ((v (car tail))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (begin (set! z (append (reverse head) (cdr tail))) (vector-ref v 1)) (lp (cons v head) (cdr tail))))))))) ((wow-check-key! z (key n) d t ...) (let ((v (car z))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (let ((n (vector-ref v 1))) (if (and t ...) (begin (set! z (cdr z)) (vector-ref v 1)) (error "check-lambda[*]: bad argument" n 'n 't ...))) (let lp ((head (list v)) (tail (cdr z))) (if (null? tail) d (let ((v (car tail))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (let ((n (vector-ref v 1))) (if (and t ...) (begin (set! z (append (reverse head) (cdr tail))) (vector-ref v 1)) (error "check-lambda[*]: bad argument" n 'n 't ...))) (lp (cons v head) (cdr tail))))))))))) (define-syntax check-opt (syntax-rules () ((check-opt z (nd ...) (#((key n) d t ...)) bd ...) (let (nd ... (n (if (null? z) d (if (null? (cdr z)) (wow-check (key n) (car z) t ...) (error "check-lambda: too many arguments" (cdr z)))))) bd ...)) ((check-opt z (nd ...) (#(n d t ...)) bd ...) (let (nd ... (n (if (null? z) d (if (null? (cdr z)) (wow-check n (car z) t ...) (error "check-lambda: too many arguments" (cdr z)))))) bd ...)) ((check-opt z (nd ...) (#((key n) d t ...) . e) bd ...) (let ((x (if (null? z) d (wow-check-key! z (key n) d t ...)))) (check-opt z (nd ... (n x)) e bd ...))) ((check-opt z (nd ...) (#(n d t ...) . e) bd ...) (let ((y (if (null? z) z (cdr z))) (x (if (null? z) d (wow-check n (car z) t ...)))) (check-opt y (nd ... (n x)) e bd ...))) ((check-opt z (nd ...) e bd ...) (let (nd ... (e z)) bd ...)))) (define-syntax check-opt* (syntax-rules () ((check-opt* z (#((key n) d t ...)) bd ...) (let ((n (if (null? z) d (if (null? (cdr z)) (wow-check (key n) (car z) t ...) (error "check-lambda*: too many arguments" (cdr z)))))) bd ...)) ((check-opt* z (#(n d t ...)) bd ...) (let ((n (if (null? z) d (if (null? (cdr z)) (wow-check n (car z) t ...) (error "check-lambda*: too many arguments" (cdr z)))))) bd ...)) ((check-opt* z (#((key n) d t ...) . e) bd ...) (let ((n (if (null? z) d (wow-check-key! z (key n) d t ...)))) (check-opt* z e bd ...))) ((check-opt* z (#(n d t ...) . e) bd ...) (let ((y (if (null? z) z (cdr z))) (n (if (null? z) d (wow-check n (car z) t ...)))) (check-opt* y e bd ...))) ((check-opt* z e bd ...) (let ((e z)) bd ...)))) (define-syntax check-lambda (syntax-rules () ((check-lambda (#((key n) d t ...) . e) bd ...) (check-lambda "chk" () () () (#((key n) d t ...)) e bd ...)) ((check-lambda (#(n d t ...) . e) bd ...) (check-lambda "chk" () () (#(n d t ...)) () e bd ...)) ((check-lambda ((n t ...) . e) bd ...) (check-lambda "chk" (tt) ((n t ...)) () () e bd ...)) ((check-lambda (n . e) bd ...) (check-lambda "chk" (tt) ((n)) () () e bd ...)) ((check-lambda "chk" (tt ...) (nt ...) (v ...) (k ...) (#((key n) d t ...) . e) bd ...) (check-lambda "chk" (tt ...) (nt ...) (v ...) (k ... #((key n) d t ...)) e bd ...)) ((check-lambda "chk" (tt ...) (nt ...) (v ...) () (#(n d t ...) . e) bd ...) (check-lambda "chk" (tt ...) (nt ...) (v ... #(n d t ...)) () e bd ...)) ((check-lambda "chk" (tt ...) (nt ...) (v ...) (k ...) (#(n d t ...) . e) bd ...) (error "check-lambda: positional argument should precede named argument")) ((check-lambda "chk" (tt ...) (nt ...) () () ((n t ...) . e) bd ...) (check-lambda "chk" (tt ... tn) (nt ... (n t ...)) () () e bd ...)) ((check-lambda "chk" (tt ...) (nt ...) () () (n . e) bd ...) (check-lambda "chk" (tt ... tn) (nt ... (n)) () () e bd ...)) ((check-lambda "chk" () () (v ...) (k ...) e bd ...) (lambda z (check-opt z () (v ... k ... . e) bd ...))) ((check-lambda "chk" (tt ...) ((n) ...) () () e bd ...) (lambda (n ... . e) bd ...)) ((check-lambda "chk" (tt ...) ((n) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (check-opt te ((n tt) ...) (v ... k ... . e) bd ...))) ((check-lambda "chk" (tt ...) ((n t ...) ...) () () () bd ...) (lambda (tt ...) (let ((n (wow-check n tt t ...)) ...) bd ...))) ((check-lambda "chk" (tt ...) ((n t ...) ...) () () e bd ...) (lambda (tt ... . te) (let ((n (wow-check n tt t ...)) ... (e te)) bd ...))) ((check-lambda "chk" (tt ...) ((n t ...) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (let ((tt (wow-check n tt t ...)) ...) (check-opt te ((n tt) ...) (v ... k ... . e) bd ...)))) ((check-lambda e bd ...) (lambda e bd ...)))) (define-syntax check-lambda* (syntax-rules () ((check-lambda* (#((key n) d t ...) . e) bd ...) (check-lambda* "chk" () () () (#((key n) d t ...)) e bd ...)) ((check-lambda* (#(n d t ...) . e) bd ...) (check-lambda* "chk" () () (#(n d t ...)) () e bd ...)) ((check-lambda* ((n t ...) . e) bd ...) (check-lambda* "chk" (tt) ((n t ...)) () () e bd ...)) ((check-lambda* (n . e) bd ...) (check-lambda* "chk" (tt) ((n)) () () e bd ...)) ((check-lambda* "chk" (tt ...) (nt ...) (v ...) (k ...) (#((key n) d t ...) . e) bd ...) (check-lambda* "chk" (tt ...) (nt ...) (v ...) (k ... #((key n) d t ...)) e bd ...)) ((check-lambda* "chk" (tt ...) (nt ...) (v ...) () (#(n d t ...) . e) bd ...) (check-lambda* "chk" (tt ...) (nt ...) (v ... #(n d t ...)) () e bd ...)) ((check-lambda* "chk" (tt ...) (nt ...) (v ...) (k ...) (#(n d t ...) . e) bd ...) (error "check-lambda*: positional argument should precede named argument")) ((check-lambda* "chk" (tt ...) (nt ...) () () ((n t ...) . e) bd ...) (check-lambda* "chk" (tt ... tn) (nt ... (n t ...)) () () e bd ...)) ((check-lambda* "chk" (tt ...) (nt ...) () () (n . e) bd ...) (check-lambda* "chk" (tt ... tn) (nt ... (n)) () () e bd ...)) ((check-lambda* "chk" () () (v ...) (k ...) e bd ...) (lambda z (check-opt* z (v ... k ... . e) bd ...))) ((check-lambda* "chk" (tt ...) ((n) ...) () () () bd ...) (lambda (tt ...) (let* ((n tt) ...) bd ...))) ((check-lambda* "chk" (tt ...) ((n) ...) () () e bd ...) (lambda (tt ... . te) (let* ((n tt) ... (e te)) bd ...))) ((check-lambda* "chk" (tt ...) ((n) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (let* ((n tt) ...) (check-opt* te (v ... k ... . e) bd ...)))) ((check-lambda* "chk" (tt ...) ((n t ...) ...) () () () bd ...) (lambda (tt ...) (let* ((n (wow-check n tt t ...)) ...) bd ...))) ((check-lambda* "chk" (tt ...) ((n t ...) ...) () () e bd ...) (lambda (tt ... . te) (let* ((n (wow-check n tt t ...)) ... (e te)) bd ...))) ((check-lambda* "chk" (tt ...) ((n t ...) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (let* ((n (wow-check n tt t ...)) ...) (check-opt* te (v ... k ... . e) bd ...)))) ((check-lambda* e bd ...) (lambda e bd ...)))) (define-syntax wow-float-key! (syntax-rules () ((wow-float-key! z (key n) d) (let ((v (car z))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (begin (set! z (cdr z)) (vector-ref v 1)) (let lp ((head (list v)) (tail (cdr z))) (if (null? tail) d (let ((v (car tail))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0))) (begin (set! z (append (reverse head) (cdr tail))) (vector-ref v 1)) (lp (cons v head) (cdr tail))))))))) ((wow-float-key! z (key n) d t ...) (let ((v (car z))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0)) (let ((n (vector-ref v 1))) (and t ...))) (begin (set! z (cdr z)) (vector-ref v 1)) (let lp ((head (list v)) (tail (cdr z))) (if (null? tail) d (let ((v (car tail))) (if (and (vector? v) (= 2 (vector-length v)) (eq? 'key (vector-ref v 0)) (let ((n (vector-ref v 1))) (and t ...))) (begin (set! z (append (reverse head) (cdr tail))) (vector-ref v 1)) (lp (cons v head) (cdr tail))))))))) ((wow-float-key! z n d) (let ((n (car z))) (set! z (cdr z)) n)) ((wow-float-key! z n d t ...) (let ((n (car z))) (if (and t ...) (begin (set! z (cdr z)) n) (let lp ((head (list n)) (tail (cdr z))) (if (null? tail) d (let ((n (car tail))) (if (and t ...) (begin (set! z (append (reverse head) (cdr tail))) n) (lp (cons n head) (cdr tail))))))))))) (define-syntax float-opt (syntax-rules () ((float-opt z (nd ...) (#((key n) d t ...)) bd ...) (let (nd ... (n (if (null? z) d (if (null? (cdr z)) (wow-check (key n) (car z) t ...) (error "float-lambda: too many arguments" (cdr z)))))) bd ...)) ((float-opt z (nd ...) (#(n d t ...)) bd ...) (let (nd ... (n (if (null? z) d (if (null? (cdr z)) (wow-check n (car z) t ...) (error "float-lambda: too many arguments" (cdr z)))))) bd ...)) ((float-opt z (nd ...) (#((key n) d t ...) . e) bd ...) (let ((x (if (null? z) d (wow-float-key! z (key n) d t ...)))) (float-opt z (nd ... (n x)) e bd ...))) ((float-opt z (nd ...) (#(n d t ...) . e) bd ...) (let ((x (if (null? z) d (wow-float-key! z n d t ...)))) (float-opt z (nd ... (n x)) e bd ...))) ((float-opt z ((n d) ...) e bd ...) (let ((n d) ... (e z)) bd ...)))) (define-syntax float-opt* (syntax-rules () ((float-opt* z (#((key n) d t ...)) bd ...) (let ((n (if (null? z) d (if (null? (cdr z)) (wow-check (key n) (car z) t ...) (error "float-lambda*: too many arguments" (cdr z)))))) bd ...)) ((float-opt* z (#(n d t ...)) bd ...) (let ((n (if (null? z) d (if (null? (cdr z)) (wow-check n (car z) t ...) (error "float-lambda*: too many arguments" (cdr z)))))) bd ...)) ((float-opt* z (#((key n) d t ...) . e) bd ...) (let ((n (if (null? z) d (wow-float-key! z (key n) d t ...)))) (float-opt* z e bd ...))) ((float-opt* z (#(n d t ...) . e) bd ...) (let ((n (if (null? z) d (wow-float-key! z n d t ...)))) (float-opt* z e bd ...))) ((float-opt* z e bd ...) (let ((e z)) bd ...)))) (define-syntax wow-float! (syntax-rules () ((wow-float! z n) (let ((n (car z))) (set! z (cdr z)) n)) ((wow-float! z n t ...) (let ((n (car z))) (if (and t ...) (begin (set! z (cdr z)) n) (let lp ((head (list n)) (tail (cdr z))) (if (null? tail) (error "float-lambda[*]: no more argument to check" 'n 't ... (reverse head)) (let ((n (car tail))) (if (and t ...) (begin (set! z (append (reverse head) (cdr tail))) n) (lp (cons n head) (cdr tail))))))))))) (define-syntax slet (syntax-rules () ((slet ((n v) ...) bd ...) (slet "sequential" () ((n v) ...) bd ...)) ((slet "sequential" (nt ...) ((n v) nv ...) bd ...) ((lambda (t) (slet "sequential" (nt ... (n t)) (nv ...) bd ...)) v)) ((slet "sequential" ((n t) ...) () bd ...) ((lambda (n ...) bd ...) t ...)))) (define-syntax float-lambda (syntax-rules () ((float-lambda (#((key n) d t ...) . e) bd ...) (float-lambda "chk" () () () (#((key n) d t ...)) e bd ...)) ((float-lambda (#(n d t ...) . e) bd ...) (float-lambda "chk" () () (#(n d t ...)) () e bd ...)) ((float-lambda ((n t ...) . e) bd ...) (float-lambda "chk" (tt) ((n t ...)) () () e bd ...)) ((float-lambda (n . e) bd ...) (float-lambda "chk" (tt) ((n)) () () e bd ...)) ((float-lambda "chk" (tt ...) (nt ...) (v ...) (k ...) (#((key n) d t ...) . e) bd ...) (float-lambda "chk" (tt ...) (nt ...) (v ...) (k ... #((key n) d t ...)) e bd ...)) ((float-lambda "chk" (tt ...) (nt ...) (v ...) () (#(n d t ...) . e) bd ...) (float-lambda "chk" (tt ...) (nt ...) (v ... #(n d t ...)) () e bd ...)) ((float-lambda "chk" (tt ...) (nt ...) (v ...) (k ...) (#(n d t ...) . e) bd ...) (error "float-lambda: positional argument should precede named argument")) ((float-lambda "chk" (tt ...) (nt ...) () () ((n t ...) . e) bd ...) (float-lambda "chk" (tt ... tn) (nt ... (n t ...)) () () e bd ...)) ((float-lambda "chk" (tt ...) (nt ...) () () (n . e) bd ...) (float-lambda "chk" (tt ... tn) (nt ... (n)) () () e bd ...)) ((float-lambda "chk" () () (v ...) (k ...) e bd ...) (lambda z (float-opt z () (v ... k ... . e) bd ...))) ((float-lambda "chk" (tt ...) ((n) ...) () () e bd ...) (lambda (n ... . e) bd ...)) ((float-lambda "chk" (tt ...) ((n) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (float-opt te ((n tt) ...) (v ... k ... . e) bd ...))) ((float-lambda "chk" (tt ...) ((n t ...) ...) () () () bd ...) (lambda (tt ...) (let ((z (list tt ...))) ;; not for random order evaluation ;; but for sequential evaluation from right to left ;;(slet ((n (wow-float! z n t ...)) ...) bd ...)))) (let ((n (wow-float! z n t ...)) ...) bd ...)))) ((float-lambda "chk" (tt ...) ((n t ...) ...) () () e bd ...) (lambda (tt ... . te) (let ((z (list tt ...))) ;;(slet ((n (wow-float! z n t ...)) ... (e te)) bd ...)))) (let ((n (wow-float! z n t ...)) ... (e te)) bd ...)))) ((float-lambda "chk" (tt ...) ((n t ...) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (let ((z (list tt ...))) ;;(slet ((tt (wow-float! z n t ...)) ...) (let ((tt (wow-float! z n t ...)) ...) (float-opt te ((n tt) ...) (v ... k ... . e) bd ...))))) ((float-lambda e bd ...) (lambda e bd ...)))) (define-syntax float-lambda* (syntax-rules () ((float-lambda* (#((key n) d t ...) . e) bd ...) (float-lambda* "chk" () () () (#((key n) d t ...)) e bd ...)) ((float-lambda* (#(n d t ...) . e) bd ...) (float-lambda* "chk" () () (#(n d t ...)) () e bd ...)) ((float-lambda* ((n t ...) . e) bd ...) (float-lambda* "chk" (tt) ((n t ...)) () () e bd ...)) ((float-lambda* (n . e) bd ...) (float-lambda* "chk" (tt) ((n)) () () e bd ...)) ((float-lambda* "chk" (tt ...) (nt ...) (v ...) (k ...) (#((key n) d t ...) . e) bd ...) (float-lambda* "chk" (tt ...) (nt ...) (v ...) (k ... #((key n) d t ...)) e bd ...)) ((float-lambda* "chk" (tt ...) (nt ...) (v ...) () (#(n d t ...) . e) bd ...) (float-lambda* "chk" (tt ...) (nt ...) (v ... #(n d t ...)) () e bd ...)) ((float-lambda* "chk" (tt ...) (nt ...) (v ...) (k ...) (#(n d t ...) . e) bd ...) (error "float-lambda*: positional argument should precede named argument")) ((float-lambda* "chk" (tt ...) (nt ...) () () ((n t ...) . e) bd ...) (float-lambda* "chk" (tt ... tn) (nt ... (n t ...)) () () e bd ...)) ((float-lambda* "chk" (tt ...) (nt ...) () () (n . e) bd ...) (float-lambda* "chk" (tt ... tn) (nt ... (n)) () () e bd ...)) ((float-lambda* "chk" () () (v ...) (k ...) e bd ...) (lambda z (float-opt* z (v ... k ... . e) bd ...))) ((float-lambda* "chk" (tt ...) ((n) ...) () () () bd ...) (lambda (tt ...) (let* ((n tt) ...) bd ...))) ((float-lambda* "chk" (tt ...) ((n) ...) () () e bd ...) (lambda (tt ... . te) (let* ((n tt) ... (e te)) bd ...))) ((float-lambda* "chk" (tt ...) ((n) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (let* ((n tt) ...) (float-opt* te (v ... k ... . e) bd ...)))) ((float-lambda* "chk" (tt ...) ((n t ...) ...) () () () bd ...) (lambda (tt ...) (let ((z (list tt ...))) (let* ((n (wow-float! z n t ...)) ...) bd ...)))) ((float-lambda* "chk" (tt ...) ((n t ...) ...) () () e bd ...) (lambda (tt ... . te) (let ((z (list tt ...))) (let* ((n (wow-float! z n t ...)) ... (e te)) bd ...)))) ((float-lambda* "chk" (tt ...) ((n t ...) ...) (v ...) (k ...) e bd ...) (lambda (tt ... . te) (let ((z (list tt ...))) (let* ((n (wow-float! z n t ...)) ...) (float-opt* te (v ... k ... . e) bd ...))))) ((float-lambda* e bd ...) (lambda e bd ...)))) (define-syntax cond-lambda (syntax-rules () ((cond-lambda (formals bd ...) cl ...) (lambda z (let ((len (length z))) (cond-lambda "*" z len (formals bd ...) cl ...)))) ((cond-lambda "*" z len (() bd ...) cl ...) (if (= len 0) ((lambda () bd ...)) (cond-lambda "*" z len cl ...))) ((cond-lambda "*" z len (((n t ...) . e) bd ...) cl ...) (cond-lambda " " z len (tt) ((n t ...)) (e bd ...) cl ...)) ((cond-lambda "*" z len ((n . e) bd ...) cl ...) (cond-lambda " " z len (tt) ((n)) (e bd ...) cl ...)) ((cond-lambda "*" z len (e bd ...) cl ...) (let ((e z)) bd ...)) ((cond-lambda "*" z len) (error "the arguments are not matched to any clause of cond-lambda" z)) ((cond-lambda " " z len (tt ...) (nt ...) (((n t ...) . e) bd ...) cl ...) (cond-lambda " " z len (tt ... tn) (nt ... (n t ...)) (e bd ...) cl ...)) ((cond-lambda " " z len (tt ...) (nt ...) ((n . e) bd ...) cl ...) (cond-lambda " " z len (tt ... tn) (nt ... (n)) (e bd ...) cl ...)) ((cond-lambda " " z len (tt ...) ((n) ...) (() bd ...) cl ...) (if (= len (length '(tt ...))) (apply (lambda (n ...) bd ...) z) (cond-lambda "*" z len cl ...))) ((cond-lambda " " z len (tt ...) ((n t ...) ...) (() bd ...) cl ...) (if (and (= len (length '(tt ...))) (apply (lambda (tt ...) (and (let ((n tt)) (and t ...)) ...)) z)) (apply (lambda (n ...) bd ...) z) (cond-lambda "*" z len cl ...))) ((cond-lambda " " z len (tt ...) ((n) ...) (e bd ...) cl ...) (if (>= len (length '(tt ...))) (apply (lambda (n ... . e) bd ...) z) (cond-lambda "*" z len cl ...))) ((cond-lambda " " z len (tt ...) ((n t ...) ...) (e bd ...) cl ...) (if (and (>= len (length '(tt ...))) (apply (lambda (tt ...) (and (let ((n tt)) (and t ...)) ...)) z)) (apply (lambda (n ... . e) bd ...) z) (cond-lambda "*" z len cl ...))))) (define-syntax cond-and* (syntax-rules () ((cond-and* ((n v t ...))) (let ((n v)) (and t ...))) ((cond-and* ((n v t ...) nvt ...)) (let ((n v)) (and t ... (cond-and* (nvt ...))))))) (define-syntax cond-lambda* (syntax-rules () ((cond-lambda* (formals bd ...) cl ...) (lambda z (let ((len (length z))) (cond-lambda* "*" z len (formals bd ...) cl ...)))) ((cond-lambda* "*" z len (() bd ...) cl ...) (if (= len 0) ((lambda () bd ...)) (cond-lambda* "*" z len cl ...))) ((cond-lambda* "*" z len (((n t ...) . e) bd ...) cl ...) (cond-lambda* " " z len (tt) ((n t ...)) (e bd ...) cl ...)) ((cond-lambda* "*" z len ((n . e) bd ...) cl ...) (cond-lambda* " " z len (tt) ((n)) (e bd ...) cl ...)) ((cond-lambda* "*" z len (e bd ...) cl ...) (let ((e z)) bd ...)) ((cond-lambda* "*" z len) (error "the arguments are not matched to any clause of cond-lambda*" z)) ((cond-lambda* " " z len (tt ...) (nt ...) (((n t ...) . e) bd ...) cl ...) (cond-lambda* " " z len (tt ... tn) (nt ... (n t ...)) (e bd ...) cl ...)) ((cond-lambda* " " z len (tt ...) (nt ...) ((n . e) bd ...) cl ...) (cond-lambda* " " z len (tt ... tn) (nt ... (n)) (e bd ...) cl ...)) ((cond-lambda* " " z len (tt ...) ((n) ...) (() bd ...) cl ...) (if (= len (length '(tt ...))) (apply (lambda (tt ...) (let* ((n tt) ...) bd ...)) z) (cond-lambda* "*" z len cl ...))) ((cond-lambda* " " z len (tt ...) ((n t ...) ...) (() bd ...) cl ...) (if (and (= len (length '(tt ...))) (apply (lambda (tt ...) (cond-and* ((n tt t ...) ...))) z)) (apply (lambda (tt ...) (let* ((n tt) ...) bd ...)) z) (cond-lambda* "*" z len cl ...))) ((cond-lambda* " " z len (tt ...) ((n) ...) (e bd ...) cl ...) (if (>= len (length '(tt ...))) (apply (lambda (tt ... . te) (let* ((n tt) ... (e te)) bd ...)) z) (cond-lambda* "*" z len cl ...))) ((cond-lambda* " " z len (tt ...) ((n t ...) ...) (e bd ...) cl ...) (if (and (>= len (length '(tt ...))) (apply (lambda (tt ...) (cond-and* ((n tt t ...) ...))) z)) (apply (lambda (tt ... . te) (let* ((n tt) ... (e te)) bd ...)) z) (cond-lambda* "*" z len cl ...))))) References [R5RS] Richard Kelsey, William Clinger, and Jonathan Rees: Revised(5) Report on the Algorithmic Language Scheme http://www.schemers.org/Documents/Standards/R5Rs/ [SRFI 16] Lars T Hansen: Syntax for procedures of variable arity. http://srfi.schemers.org/srfi-16/ [SRFI 51] Joo ChurlSoo: Handling rest list. http://srfi.schemers.org/srfi-51/ Scsh Olin Shivers, Brian Carlstrom, Martin Gasbichler, Mike Sperber http://www.scsh.net Copyright Copyright (c) 2006 Joo ChurlSoo. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.