読者です 読者をやめる 読者になる 読者になる

名前付き引数

先日は Scheme でオプショナル引数をマクロ展開時にデフォルト値に置き換えるマクロを書いた。

http://saito.hatenablog.jp/entry/20110629/1309355746

今度は名前付き引数で同様の処理を行うマクロを考えた。

つまり、具体的なコードで表すと、

(define/named-arguments (sample a1 a2 :key (:key1 value1 3) (:key2 value2 4))
  (list a1 a2 value1 value2))

(sample 1 2 :key1 100)

が、

(define (t a1 a2 value1 value2)
  (list a1 a2 value1 value2))

(t 1 2 100 4)

に展開されるようなマクロである。

キーワード :key1 と共に渡した 100 という値が value1 という変数を束縛し、省略した :key2 の方はデフォルト値である 4 が使われるわけだ。

引数の途中に :key が現れるとそれ以降は名前付き引数であり

  • キーワード
  • 変数名
  • デフォルト引数

の三つ組で表される。
実装はこちら。

(define-syntax def%%
  (syntax-rules ()
    ((_ name t (args ...) ((k d) ...) ((rk rv)  ...))
     (letrec-syntax ((hoge (syntax-rules (rk ...)
                             ((_ (ac (... ...)))
                              (t args ... ac (... ...)))
                             ((_ (ac (... ...)) (rk x) r (... ...))
                              (hoge (ac (... ...) rv) r (... ...)))
                             ...
                             ((_ (ac (... ...)) (_ x) r (... ...))
                              (hoge (ac (... ...) x) r (... ...))))))
       (hoge () (k d) ...)))
    ((_ name t args ((k d) ...) (ac ...) rk rv r ...)
     (def%% name t args ((k d) ...) (ac ... (rk rv)) r ...))))

(define-syntax def%
  (syntax-rules (:key)
    ((_ name (args ...) (:key (key var default) ...) body ...)
     (begin
       (define (t args ... var ...) body ...)
       (define-syntax name
         (syntax-rules (key ...)
           ((_ args ... ra (... ...))
            (def%% name t
              (args ...) ((key default) ...) () ra (... ...)))))))
    ((_ name (ac ...) (a . r) body ...)
     (def% name (ac ... a) r body ...))
    ((_ name (ac ...) r body ...)
     (define name (lambda(ac ... . r) body ...)))))

(define-syntax define/named-arguments
  (syntax-rules ()
    ((_ (name . args) body ...)
     (def% name () args body ...))))

Document ID: 247ae31935472bcb2822dcfcca3cce18