[Gauche-devel-jp] 初心者質問:マクロ構文とlambdaの引数について

アーカイブの一覧に戻る

Shiro Kawai shiro****@lava*****
2003年 1月 16日 (木) 14:52:38 JST


From: Makoto Satoh <makot****@yahoo*****>
Subject: [Gauche-devel-jp] 初心者質問:マクロ構文とlambdaの引数について
Date: Thu, 16 Jan 2003 13:31:01 +0900 (JST)

>  (define-syntax define-reader-macro 
>    (syntax-rules ()
>      ((_ (name . args) . body)
>       (set! *reader-macro-alist*
>             (let ((sname (string-append "$$" (symbol->string 'name))))
>               (acons sname
>                      (lambda p
>                        (if (arity-matches? p 'args)
>                            (receive args (apply values p) . body)
>                            (unrecognized sname)))
>                      *reader-macro-alist*))))
>      ))
> 
> ここで、3行目の _ は、マクロ名、つまりここでは define-reader-macro を
> 参照していると考えて良いでしょうか?

R5RSでは、syntax-rulesのパターンの最初のidentifierは単なる
placeholderであり、何も参照しません。ここにマクロ名を持って来る
書き方もありますが(R5RSでもそうなっている)、どうせ何も参照しない
からと `_' を置く書き方もよく見ます。

何故最初のidentifierが特別扱いかはR5RSの4.3.2のRationale以降に
説明されています。スコープルールが変になるからだそうです。

> また、let 文の中では、グローバル変数 *reader-macro-alist* に、sname と
> lambda 式の戻り値を acons していますが、lambda 式の引数 p には、何が
> どこから来るのでしょうか?

lambda式の戻り値はただの手続きですね。define-reader-macroがやっている
ことは、*reader-macro-alist* に

  (("$$name1" . #<手続き1>) ("$$name2" . #<手続き2>) ....)

という構造を足して言っているだけで、手続きが実際にどう呼ばれているかは
ここを見ているだけではわかりません。

そのちょっと上を見るとこんなのがあります。

(define (handle-reader-macro name)
  (let1 args (string-tokenize name)
    (cond ((assoc (car args) *reader-macro-alist*)
           => (lambda (p) (apply (cdr p) (cdr args))))
          (else (unrecognized name)))))

handle-reader-macroに渡された文字列がまず単語に分解され、
その先頭の要素でもって *reader-macro-alist* が探されます。
例えば(car args)が"$$name2"だったとすると、assocの
戻り値は ("$$name2" . #<手続き2>) になり、それが
(lambda (p) ....) に渡されます。その中で

  (apply (cdr p) (cdr args))

としています。(cdr p) は #<手続き2> であり、これが
define-reader-macroの中で作られた手続きになっています。
したがってその手続きに渡される引数は、(cdr args) です。

ではargsには具体的に何が入っているのか? これはhandle-reader-macro
が呼ばれているところを探せばわかります。それはwiliki.scm内にあります。

(define (reader-macro-wiki-name? name)
  (cond ((string-prefix? "$$" name)
         (handle-reader-macro name))
        ((or (string-index name #[\s])
             (string-prefix? "$" name))
         ;;invalid wiki name
         #`"[[,(html-escape-string name)]]")
        (else #f)))

この調子で辿ってゆけば良いのですがそこらへんを端折ると、wilikiの
フォーマッタは "[[ほげほげ]]" という文字列を見つけると

 (reader-macro-wiki-name? "ほげほげ")

を呼び出します。ここで「ほげほげ」が "$$" で始まっていた場合、
例えば "$$index Scheme:" であった場合に、handle-reader-macro
が呼ばれるわけです。handle-reader-macro内ではstring-tokenize
によって上の文字列は

  ("$$index" "Scheme:")

となり、その先頭の要素が *reader-macro-alist* の検索に使われ、
残りの要素がマクロを処理するlambdaへと渡されます。

> あるいは、Scheme について初心者が質問できる他の場所があれば、教えて
> いただけますか?

ここでも構いませんし、WiLiKiでもいいと思います。

--shiro




Gauche-devel-jp メーリングリストの案内
アーカイブの一覧に戻る