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
----------------------------------------------------------------

Reply via email to