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