For the record, I eventually came up with the following code: (define-module (extra define-keywords) #:use-module (ice-9 nice-9) #:use-module (extra attributes) #:replace ((define/keywords . define*)))
(define-syntax define/keywords (lambda (x) (define* (required args #:optional (gathered '())) (match args (((? symbol?) #:= . _) (values (reverse gathered) args)) (((? symbol? s) . rest) (required rest `(,s . ,gathered))) (_ (values (reverse gathered) args)))) (define* (optional args #:optional (gathered '())) (match args (((? symbol? s) #:= value . rest) (optional rest `((,s ,value) . ,gathered))) (_ (values (reverse gathered) args)))) (define* (keyword args #:optional (gathered '())) (match args (((? keyword? k) (? symbol? s) #:= value . rest) (keyword rest `((,s ,value ,k) . ,gathered))) (((? keyword? k) (? symbol? s) . rest) (keyword rest `((,s #f ,k) . ,gathered))) (_ (values (reverse gathered) args)))) (define (required+optional+keyword+rest+keys args) (let* ((required args* (required (syntax->datum args))) (optional args** (optional args*)) (keyword rest (keyword args**)) (((names values keys) ...) keyword)) (datum->syntax x `(,required ,optional ,keyword ,rest ,keys)))) (syntax-case x () ((_ (proc . args) body ...) (with-syntax ((((required ...) (optional ...) (keyword ...) rest keys) (required+optional+keyword+rest+keys #'args))) #'(define proc (lambda* (required ... #:optional optional ... #:key keyword ... #:allow-other-keys . rest) (let ((rest (remove-attributes 'keys rest))) body ...)))))))) In addition to removing the supported keywords from the "rest" list, it provides an alternative (incompatible) syntax for optional and keyword arguments: (define* (f r1 r2 r3 opt1 #:= 1 opt2 #:= 2 #:key1 k1 #:key2 k2 #:= 7) ...) where r1, r2 and r3 are required, opt1 and opt2 optional (with default values of 1 and 2, respectively), and variables k1 and k2 are accessible via #:key1 and #:key2 keywords, where in addition k2 has a default value 7. I'm not sure whether the use of #:= keyword is a good idea -- probably not. But I'm not a big fan of the current syntax either. The definition requires the (ice-9 nice-9) library, which -- traditionally -- can be found here: https://github.com/panicz/pamphlet/blob/master/libraries/ice-9/nice-9.scm In addition, it requires a definition of "remove-attributes": (define (remove-attributes attributes #;from attribute-list) (match attribute-list (((? keyword? key) value . rest) (if (member key attributes) (remove-attributes attributes rest) `(,key ,value . ,(remove-attributes attributes #;from rest)))) (_ attribute-list)))