Hi list,

I've enhanced my (newer) keywords arguments library to optimize
processing at expand-time, which significantly reduces the run-time
cost, and I want to show it off now :-)  Also, unlike my previous
keywords library, this one does not use the clunky [:- [kw ---] ...]
syntax I for some reason found amusing, and it is more generalized.  I'm
still not decided if the semantics of "additional" (analog to "rest")
arguments are how they should be, see my question at the end.


Ikarus Scheme version 0.0.3+ (revision 1693, build 2008-11-25)
Copyright (c) 2006-2008 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 ())
> (f0 1 2 'b 3)
Unhandled exception
 Condition components:
   1. &assertion
   2. &who: f0
   3. &message: "missing required keyword"
   4. &keyword: a
> (f0 1 2 'a 3 'b)
Unhandled exception
 Condition components:
   1. &assertion
   2. &who: f0
   3. &message: "keyword missing value"
   4. &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 "ignored" 'c 'ignored 'b "zab")
(1 2 3 "zab" #t)
> (f1 1 2 "ignored" 'c 'ignored 'b #\λ 'a 'blah)
(1 2 blah #\λ #t)
> (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: (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)
>
> (define first-class (car (let ([x f1]) (list x))))
> (first-class 1 2 "ignored" 'c 'ignored 'b #\λ 'a 'blah)
(1 2 blah #\λ #t)
> (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: (if (number? a) string? char?)
   6. &irritants: (oops)
> 
> (define f2
    (lambda/kw (x [a] . r)  ;; always run-time processing
      (apply + x a r)))
> (f2 1 2 3 'a 4 5)
15
>
> (define f3
    (case-lambda/kw         ;; always 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 "λ")
#("λ")
> (f3 1 'b 'c 2 "foo" 'd "bar")
("bar" d "foo" 2 c b 1)
> 
> (define f4
    (case-lambda/kw
      [([a]) 'first]
      [([b] [c]) 'second]))
> 
> (f4 'c 1 'a 2 'b 3)
first
> (f4 'c 1 'b 3)
second
> (f4 'c 1)
Unhandled exception
 Condition components:
   1. &assertion
   2. &who: "a case-lambda/kw procedure"
   3. &message: "no clause matches arguments"
   4. &irritants: (c 1)
> 
> (define n #e1e7)
> (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
    144 ms elapsed cpu time, including 0 ms collecting
    162 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)):
    96 collections
    652 ms elapsed cpu time, including 81 ms collecting
    682 ms elapsed real time, including 95 ms collecting
    400000000 bytes allocated
;; Mostly all processed 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)):
    95 collections
    901 ms elapsed cpu time, including 20 ms collecting
    993 ms elapsed real time, including 23 ms collecting
    400000000 bytes allocated
;; All processed 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)):
    1223 collections
    21605 ms elapsed cpu time, including 536 ms collecting
    23213 ms elapsed real time, including 532 ms collecting
    5120004096 bytes allocated
;; case-lambda/kw is even more costly
> (time (big-loop (f3 1 'a "λ")))
running stats for (big-loop (f3 1 'a "λ")):
    2141 collections
    39535 ms elapsed cpu time, including 2053 ms collecting
    42176 ms elapsed real time, including 2099 ms collecting
    8960008672 bytes allocated
>
;; Keywords arguments lists 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"))
(1 2 3 -3 #f)
> (f1 1 2 (begin (display "ran\n") 'ignored))
(1 2 3 -3 #f)
> (f1 1 2 'a (begin (display "ran\n") 'evaled) 'b #\c)
ran
(1 2 evaled #\c #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
> 


Question: Do you think additionals should cause an error if the
keyword-formals do not specify taking an "additionals" argument?  This
would also change the semantics of case-lambda/kw clause selection.
Allowing additionals that are ignored seems good for possible future
uses of keywords lists where they are appended / merged with other
keywords lists that might have keywords / values that are ignored.

[Jibe at explicit phasing: Take a look at the (xitomatl keywords ---)
implementation to see what it took to make it work for explicitly phased
systems.]

As of revision 140.  Available at:
https://code.launchpad.net/~derick-eddington/ikarus-libraries/xitomatl

Thanks for any feedback,

-- 
: Derick
----------------------------------------------------------------

Reply via email to