I've changed my (xitomatl keywords) library in a few ways from how it was in my previous post (many months ago) in this thread -- run-time processing of arguments is much faster; unexpected "additionals" arguments are not allowed; and define/kw macros raise &syntax exceptions instead of &assertion. See below for examples which give an overview of it.
Available at: https://code.launchpad.net/~derick-eddington/scheme-libraries/xitomatl Ikarus Scheme version 0.0.4-rc1+ (revision 1821, build 2009-06-30) Copyright (c) 2006-2009 Abdulaziz Ghuloum > (import (xitomatl keywords)) > (define/kw (f0 x y [a] [b] . r) ;; defines f0 as a new macro (list x y a b r)) > (f0 1 2 "foo" 'b 3 'bar 4 5 'a 6) ;; expand-time processing (1 2 6 3 ("foo" bar 4 5)) > (f0 1 2 'b 3 'a 4 'b 5 'a 6 'b 7) (1 2 6 7 ()) > (expand '(f0 1 2 'b 3 "foo" 'a 4 'b 5 'a 6 'bar 'b 7) (interaction-environment)) ((top-level-value '#{proc/ve |?<zrjzQzR9lLnH!h|}) '1 '2 '6 '7 (list '"foo" 'bar)) > (f0 1 2 'b 3) Unhandled exception Condition components: 1. &who: f0 2. &message: "missing required keyword" 3. &syntax: form: (f0 1 2 'b 3) subform: #f 4. &trace: #<syntax (f0 1 2 'b 3)> 5. &keyword: a > (f0 1 2 'a 3 'b) Unhandled exception Condition components: 1. &who: f0 2. &message: "keyword missing value" 3. &syntax: form: (f0 1 2 'a 3 'b) subform: #f 4. &trace: #<syntax (f0 1 2 'a 3 'b)> 5. &keyword: b > (f0) Unhandled exception Condition components: 1. &message: "invalid syntax" 2. &syntax: form: (f0) subform: #f 3. &trace: #<syntax (f0)> ;; letrec* semantics for :default and :predicate expressions ;; referring to sibling arguments > (define/kw (f1 x y [a :default (+ x y)] [b :default (- a) :predicate (if (number? a) string? char?)] [c :boolean]) (list x y a b c)) > (f1 1 2) (1 2 3 -3 #f) > (f1 1 2 'a 54321) (1 2 54321 -54321 #f) > (f1 1 2 "extra" 'c 'extra 'b "zab") Unhandled exception Condition components: 1. &who: f1 2. &message: "unexpected additional expressions" 3. &syntax: form: (f1 1 2 "extra" 'c 'extra 'b "zab") subform: ("extra" 'extra) 4. &trace: #<syntax (f1 1 2 "extra" 'c 'extra 'b "zab")> > (f1 1 2 'b #\λ 'a 3) Unhandled exception Condition components: 1. &assertion 2. &who: f1 3. &message: "keyword predicate false" 4. &keyword: b 5. &predicate-expression: (if (number? a) string? char?) 6. &irritants: (#\λ) > (f1 1 2 'a 'blah) Unhandled exception Condition components: 1. &assertion 2. &who: - 3. &message: "not a number" 4. &irritants: (blah) ;; macros defined via define/kw are still usable as first-class procedures > (define first-class (car (let ([x f1]) (list x)))) > (first-class 1 2 'c 'b #\λ 'a 'foo) (1 2 foo #\λ #t) > (first-class 1 2 "extra" 'c 'extra 'b #\λ 'a 'blah) Unhandled exception Condition components: 1. &assertion 2. &who: f1 3. &message: "unexpected additional arguments" 4. &irritants: ("extra" extra) > (first-class 1 2 'b 'oops 'a 321) Unhandled exception Condition components: 1. &assertion 2. &who: f1 3. &message: "keyword predicate false" 4. &keyword: b 5. &predicate-expression: (if (number? a) string? char?) 6. &irritants: (oops) > (define f2 (lambda/kw (x [a] . r) ;; run-time processing (apply + x a r))) > (f2 1 2 3 'a 4 5) 15 > (define f3 (case-lambda/kw ;; run-time processing [(x [a :predicate number?]) (list x a)] [([a]) (vector a)] [r (reverse r)])) > (f3 1 'a 2) (1 2) > (f3 1 'a "λ") ("λ" a 1) > (define f4 (case-lambda/kw [([a]) 'first] [([b] [c]) 'second])) > (f4 'c 1 'b 3) second > (f4 'c 1 'a 2 'b 3) Unhandled exception Condition components: 1. &assertion 2. &who: "a case-lambda/kw procedure" 3. &message: "no clause matches arguments" 4. &irritants: (c 1 a 2 b 3) ;; mini benchmark of keywords processing > (define n #e1e8) > (define-syntax big-loop (syntax-rules () [(_ expr ...) (let loop ([i 0]) (unless (= i n) expr ... (loop (add1 i))))])) > (time (big-loop)) running stats for (big-loop): no collections 937 ms elapsed cpu time, including 0 ms collecting 996 ms elapsed real time, including 0 ms collecting 0 bytes allocated > (define (f5 x y a b c) (list x y a b c)) ;; normal procedure call > (time (big-loop (f5 1 2 3 4 5))) running stats for (big-loop (f5 1 2 3 4 5)): 956 collections 5392 ms elapsed cpu time, including 356 ms collecting 6623 ms elapsed real time, including 353 ms collecting 4000008192 bytes allocated ;; most of processing at expand-time, once > (time (big-loop (f1 1 2 'c 'b "λ" 'a 3))) running stats for (big-loop (f1 1 2 'c 'b "λ" 'a 3)): 956 collections 7052 ms elapsed cpu time, including 236 ms collecting 8534 ms elapsed real time, including 313 ms collecting 4000004096 bytes allocated ;; all processing at run-time, every call > (time (big-loop (first-class 1 2 'c 'b "λ" 'a 3))) running stats for (big-loop (first-class 1 2 'c 'b "λ" 'a 3)): 4013 collections 31710 ms elapsed cpu time, including 1005 ms collecting 38868 ms elapsed real time, including 1387 ms collecting 16800004096 bytes allocated ;; case-lambda/kw is a lot slower > (time (big-loop (f3 1 'a "λ"))) running stats for (big-loop (f3 1 'a "λ")): 23315 collections 741724 ms elapsed cpu time, including 159477 ms collecting 1049235 ms elapsed real time, including 226133 ms collecting 97600065232 bytes allocated ;; keywords arguments can be constructed > (apply f1 1 (append (list 2 'c (string->symbol "b")) (list "λ" 'a 543))) (1 2 543 "λ" #t) ;; but only for first-class/run-time, not macro/expand-time-optimized > (f1 1 2 (string->symbol "a") 543 (string->symbol "c")) Unhandled exception Condition components: 1. &who: f1 2. &message: "unexpected additional expressions" 3. &syntax: form: (f1 1 2 (string->symbol "a") 543 (string->symbol "c")) subform: ((string->symbol "a") 543 (string->symbol "c")) 4. &trace: #<syntax (f1 1 2 (string->symbol "a") 543 (string->symbol "c"))> ;; and only the expression of the last repeated keyword is evaluated > (f1 1 2 'b (begin (display "1st evaled\n") "ignored") 'b (begin (display "2nd evaled\n") "used")) 2nd evaled (1 2 3 "used" #f) ;; general keywords arguments parsing available > (define kwp (keywords-parser [a :predicate char?] [b :default 'λ] [c :boolean])) > (kwp '("foo" a #\A bar c c "zab")) #\A λ #t ("foo" bar "zab") > (kwp '()) Unhandled exception Condition components: 1. &assertion 2. &who: "a keywords parser" 3. &message: "missing required keyword" 4. &keyword: a -- : Derick ----------------------------------------------------------------
