forked from shirok/Gauche
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmacro.texi
2698 lines (2389 loc) · 111 KB
/
macro.texi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
@node Macros, Core library, Core syntax, Top
@chapter Macros
@c NODE マクロ
@c EN
Macro of Lisp-family language is very different feature from
ones of other languages, such as C preprocessor macros.
It allows you to extend the original language syntax.
You can use macros to change Gauche syntax
so that you can run a Scheme program written to other Scheme
implementations, and you can even design your own mini-language
to solve your problem easily.
@c JP
Lisp系言語のマクロは、他の言語に見られるマクロ(例えばCプリプロセッサマクロ)とは
大きく異なります。Lispのマクロは元の言語の構文を拡張する手段なのです。
例えば、Gaucheの構文を若干変えることで他のScheme実装用に書かれたSchemeプログラムを
走らせたり、あるいは自分の問題解決に適した「ミニ言語」をデザインすることさえできます。
@c COMMON
@c EN
Gauche supports hygienic macros, which allows to write safe macros
by avoiding name collisions. If you know traditional Lisp macros
but new to hygienic macros, they might seem confusing at first.
We have an introductory section (@ref{Why hygienic?}) for those who
are not familiar with hygienic macros; if you know what they are,
you can skip the section.
@c JP
Gaucheは、名前の衝突を避ける安全なマクロを簡単に書ける、「衛生的な(hygienic)」
マクロをサポートします。これは、従来のLispマクロは知っていても衛生的なマクロを
初めて見る人には、やや難解に見えるかもしれません。
衛生的マクロに馴染みが無い読者向けに、紹介の節を用意しました(@ref{Why hygienic?})。
既に衛生的マクロを知っている読者はその節は読み飛ばして構いません。
@c COMMON
@menu
* Why hygienic?::
* Hygienic macros::
* Traditional macros::
* Hybrid macros::
* Syntax parameters::
* Identifiers::
* Debugging macros::
* Macro utilities::
@end menu
@node Why hygienic?, Hygienic macros, Macros, Macros
@section Why hygienic?
@c NODE なぜ衛生的マクロか
@c EN
Lisp macro is a programmatic transformation of source code.
A @emph{macro transformer} is a procedure that takes a subtree of
source code, and returns a reconstructed tree of source code.
@c JP
Lispのマクロは、ソースコードをプログラムによって変換するものです。
@emph{マクロ変換器(macro transformer)}が、ソースコードの部分木を受け取り、
加工したソースコードの部分木を返します。
@c COMMON
@c EN
The traditional Lisp macros take the input source code as
an S-expression, and returns the output as another S-expression.
Gauche supports that type of macro, too, with @code{define-macro} form.
Here's the simple definition of @code{when} with the traditional macro.
@c JP
伝統的なLispマクロでは、入力となるソースコードも、出力されるコードも、単なるS式でした。
Gaucheはそのタイプのマクロも@code{define-macro}形式でサポートしています。
例えば、@code{when}は伝統的マクロで次のとおり書けます。
@c COMMON
@example
(define-macro (when test . body)
`(if ,test (begin ,@@body)))
@end example
@c EN
For example,
if the macro is used as @code{(when (zero? x) (print "zero") 'zero)},
the above macro transformer rewrites it to
@code{(if (zero? x) (begin (print "zero") 'zero))}. So far, so good.
@c JP
このマクロが@code{(when (zero? x) (print "zero") 'zero)}のように使われたとすれば、
上記の変換器はそれを@code{(if (zero? x) (begin (print "zero") 'zero))}と
書き換えます。一見問題なさそうですね。
@c COMMON
@c EN
But what if the @code{when} macro is used in an environment
where the names @code{begin} or @code{if} is bound to nonstandard values?
@c JP
けれども、@code{begin}や@code{if}が通常とは違う意味で束縛されている環境で
@code{when}が使われたらどうなるでしょう。
@c COMMON
@example
(let ([begin list])
(when (zero? x) (print "zero") 'zero))
@end example
@c EN
The expanded result would be as follows:
@c JP
展開結果は次の通りになります。
@c COMMON
@example
(let ([begin list])
(if (zero? x) (begin (print "zero") 'zero)))
@end example
@c EN
This obviously won't work as the macro writer intended, since
@code{begin} in the expanded code refers to the locally bound name.
@c JP
これでは意図した通りには動きません。展開された結果の中の@code{begin}が
ローカル変数と解釈されてしまいます。
@c COMMON
@c EN
This is a form of @emph{variable capture}. Note that, when Lisp
people talk about variable capture of macros, it often means
another form of capture, where the temporary variables inserted
by a macro would unintentionally capture the variables passed to
the macro. That kind of variable capture can be avoided easily
by naming the temporary variables something that never conflict,
using @code{gensym}.
@c JP
これは@emph{変数捕捉}の一形態です。Lispのマクロによる変数捕捉というと、
別の形態、すなわちマクロにより導入される一時変数がマクロに渡された式内の
変数を意図せずに捕捉してしまうことが話題に上ることが多いのですが、
そちらは@code{gensym}を使って一時変数を決して衝突しない名前にすることで
簡単に回避できます。
@c COMMON
@c EN
On the other hand, the kind of variable capture in the above example
can't be avoided by @code{gensym}, because @code{(let ([begin list]) ...)}
part isn't under macro writer's control. As a macro writer, you can
do nothing to prevent the conflict, just hoping the
macro user won't do such a thing. Sure, rebinding @code{begin} is
a crazy idea that nobody perhaps wants to do, but it can happen on
@emph{any} global variable, even the ones you define for your library.
@c JP
しかし上の例のような変数捕捉は@code{gensym}では回避できません。外側の
@code{(let ([begin list]) ...)}の部分はマクロを書く人には制御できない
からです。マクロ作成者が、この衝突を避けるために出来ることは何もありません。
せいぜい、マクロ使用者がそんな使い方をしないように祈るだけです。
もちろん、@code{begin}を再束縛するなんて誰もやろうとは思わないかもしれませんが、
同様の衝突はあなたのライブラリが提供するものも含めあらゆるグローバル変数について
起こり得るのです。
@c COMMON
@c EN
Various Lisp dialects have tried to address this issue in different
ways. Common Lisp somewhat relies on the common sense of the
programmer---you can use separate packages to reduce the chance
of accidental conflict but can't prevent the user from binding
the name in the same package.
(The Common Lisp spec says it is undefined if you locally rebind
names of CL standard symbols; but it doesn't prevent you from locally
rebinding symbols that are provided by user libraries.)
@c JP
異なるLisp方言はそれぞれ異なる方法でこの問題に対処してきました。
Common Lispは、ある意味プログラマの常識に頼ります。マクロ作成者は
ライブラリのパッケージを分けることで、偶然名前が衝突してしまう危険性を
減らせますが、マクロ使用者が同じパッケージの名前を再束縛することを防げるわけではありません。
(Common Lispの仕様ではCL標準のシンボルをローカルに再束縛した場合の
動作は未定義とされていますが、ユーザが提供するライブラリについては
何も決められていません。)
@c COMMON
@c EN
Clojure introduced a way to directly refer to the toplevel variables
by a namespace prefix, so it can bypass whatever local bindings of
the same name (also, it has a sophisticated quasiquote form that
automatically renames free variables to refer to the toplevel ones).
It works, as far as there are no local macros. With
local macros, you need a way to distinguish different local bindings
of the same name, as we see in the later examples. Clojure's way
can only distinguish between local and toplevel bindings.
It's ok for Clojure which doesn't have local macros,
but in Scheme, we prefer uniform and orthogonal axioms---if functions
can be defined locally with lexical scope, why not macros?
@c JP
Clojureは、名前空間プレフィクスによって直接トップレベル変数を参照する方法を
導入したので、同名のローカル変数束縛をバイパスして意図するトップレベル変数を確実に
参照できます (また、Clojureのquasiquoteは高機能で、自由変数を自動的に
プレフィクスつきのトップレベル変数へと変換してくれます。)
この方法はローカルマクロが存在しない限りはうまくいきます。
ローカルマクロがあると、後の例で見るように、複数の同名のローカル変数束縛を
区別する必要が出てきます。Clojureの方法はローカル変数束縛とトップレベル変数束縛を
区別できるだけです。Clojureにはローカルマクロが無いのでそれでよいのですが、
Schemeは一様で直交する定理を重視するので、レキシカルスコープを持つローカル関数があるなら、
レキシカルスコープを持つローカルマクロもやっぱり欲しいわけです。
@c COMMON
@c EN
Let's look at the local macro with lexical scope. For the sake of
explanation, suppose we have
@emph{hypothetical} local macro binding form, @code{let-macro},
that binds a local identifiers to a macro transformer.
(We don't actually have @code{let-macro}; what we have is
@code{let-syntax} and @code{letrec-syntax}, which have slightly
different way to call macro transformers. But here @code{let-macro} may
be easier to understand as it is similar to @code{define-macro}.)
@c JP
レキシカルスコープを持つローカルマクロを見てみましょう。説明のために、
ローカルなマクロ束縛を書ける@code{let-macro}という形式があると仮定します。
(実際には@code{let-macro}形式はありません。マクロ変換器の指定方法が
やや異なる@code{let-syntax}と@code{letrec-syntax}という形式があります。
ただ、ここでは@code{define-macro}と似たような形で例を示す方がわかりやすいので、
そのような@code{let-macro}があるものとして説明します。)
@c COMMON
@example
(let ([f (^x (* x x))])
(let-macro ([m (^[expr1 expr2] `(+ (f ,expr1) (f ,expr2)))])
(let ([f (^x (+ x x))])
(m 3 4)))) ; [1]
@end example
@c EN
The local identifier @var{m} is bound to a macro transformer
that takes two expressions, and returns an S-expression.
So, the @code{(m 3 4)} form [1] would be expanded into
@code{(+ (f 3) (f 4))}. Let's rewrite the above expression
with the expanded form. (After expansion, we no longer
need @code{let-macro} form, so we don't include it.)
@c JP
ローカルな識別子@var{m}は、二つの式を引数として取り、S式を返すマクロ変換器に
束縛されます。従って、[1]の@code{(m 3 4)}は
@code{(+ (f 3) (f 4))}へと展開されます。上の式を展開結果を使って
書き直してみます (展開後は@code{let-macro}フォームはもはや必要ないので
展開結果には含めていません)。
@c COMMON
@example
(let ([f (^x (* x x))])
(let ([f (^x (+ x x))])
(+ (f 3) (f 4)))) ; [2]
@end example
@c EN
Now, the question. Which binding @code{f} in the expanded form [2]
should refer? If we literally interpret the expansion,
it would refer to the inner binding @code{(^x (+ x x))}.
However, following the Scheme's scoping principle, the outer
code should be fully understood regardless of inner code:
@c JP
さてここで問題です。展開結果に現れた[2]のフォーム内の@code{f}は、どちらの
@code{f}を参照すべきでしょう。上の式を文字通り解釈するなら、
より内側にある@code{(^x (+ x x))}への束縛となります。
けれども、Schemeのスコープ規則にしたがえば、
外側のコードは、内側にどんなコードが来るかに関わらず意味が決まって欲しいわけです。
@c COMMON
@example
(let ([f (^x (* x x))])
(let-macro ([m (^[expr1 expr2] `(+ (f ,expr1) (f ,expr2)))])
@c EN
;; The code here isn't expected to accidentally alter
;; the behavior defined outside.
@c JP
;; ここに書かれたコードがうっかり外側のコードに影響を与えてしまう
;; のは避けたい。
@c COMMON
))
@end example
@c EN
The macro writer may not know the inner @code{let} shadows
the binding of @code{f} (the inner forms may be @code{include}d,
or may be changed by other person who didn't fully realize
the macro expansion needs to refer outer @code{f}).
@c JP
マクロ作成者は内側の@code{let}が@code{f}をシャドウしてしまうことを
知らないかもしれません(内側のフォームは他のコードを@code{include}している
かもしれませんし、また他の人が、ローカルマクロが外側の@code{f}を参照することに
気づかずに内側のコードを変更してしまうかもしれません。)
@c COMMON
@c EN
To ensure the local macro to work regardless of what's placed
inside @code{let-macro}, we need a sure way to refer the outer
@code{f} in the result of macro expansion. The basic idea is
to ``mark''
the names inserted by the macro transformer @code{m}---which are
@code{f} and @code{+}---so that we can distinguish two @code{f}'s.
@c JP
@code{let-macro}の中に置かれるコードが何であれローカルマクロが動作するためには、
マクロの展開結果から「外側の@code{f}」を確実に参照する方法が必要です。
基本的なアイディアは、
マクロ変換器@code{m}により挿入される名前(@code{f}と@code{+})に
「印」をつけて、二つの@code{f}を区別するというものです。
@c COMMON
@c EN
For example, if we would rewrite the entire form and @emph{renames}
corresponding local identifiers as follows:
@c JP
例えば、フォーム全体を書き直して、対応するローカル変数がユニークな名前を持つように
@emph{リネーム}したらどうでしょう:
@c COMMON
@example
(let ([f_1 (^x (* x x))])
(let-macro ([m (^[expr1 expr2] `(+ (f_1 ,expr1) (f_1 ,expr2)))])
(let ([f_2 (^x (+ x x))])
(m 3 4))))
@end example
@c EN
Then the naive expansion would correctly preserve scopes; that is,
expansion of @code{m} refers @code{f_1}, which wouldn't conflict
with inner name @code{f_2}:
@c JP
こうしておけばナイーブな展開でもスコープが正しく保たれます。つまり、
@code{m}の展開結果に現れる@code{f_1}は内側の@code{f_2}と衝突しません。
@c COMMON
@example
(let ([f_1 (^x (* x x))])
(let ([f_2 (^x (+ x x))])
(+ (f_1 3) (f_1 4))))
@end example
@c EN
(You may notice that this is similar to lambda calculus treating
lexical bindings with higher order functions.)
@c JP
(ラムダ計算において、レキシカルスコープを保ったまま高階関数を扱う際に
似たようなリネーム戦略を見たことがあるかもしれません)
@c COMMON
@c EN
The above example deal with avoiding @code{f} referred from the
macro @emph{definition} (which is, in fact, @code{f_1}) from being
shadowed
by the binding of @code{f} at the macro @emph{use} (which is @code{f_2}).
@c JP
上の例ではマクロの@emph{定義時}に現れる@code{f}(リネーム後は@code{f_1})が
マクロの@emph{使用時}に現れる@code{f} (リネーム後は@code{f_2}) によって
シャドウされることを避ける話でした。
@c COMMON
@c EN
Another type of variable capture (the one most often talked about,
and can be avoided by @code{gensym})
is that a variable in macro use site is shadowed by the binding introduced
by a macro definition. We can apply the same renaming strategy to
avoid that type of capture, too. Let's see the following example:
@c JP
一方、もう一つのタイプの変数捕捉 (より頻繁に話題に上る、@code{gensym}で回避できる捕捉)
は、マクロ使用時の変数がマクロ定義時に導入される束縛によりシャドウされてしまう
という問題です。これについても、同じリネーム戦略が使えます。
次の例を見てみましょう。
@c COMMON
@example
(let ([f (^x (* x x))])
(let-macro ([m (^[expr1] `(let ([f (^x (+ x x))]) (f ,expr1)))])
(m (f 3))))
@end example
@c EN
The local macro inserts binding of @code{f} into the expansion.
The macro use @code{(m (f 3))} also contains a reference to @code{f},
which should be the outer @code{f},
since the macro use is lexically outside of the @code{let} inserted
by the macro.
@c JP
ローカルマクロは@code{f}の束縛を導入しています。
一方、マクロの使用時@code{(m (f 3))}に、@code{f}への参照が含まれています。
後者の@code{f}は外側の@code{f}を指すべきです。なぜならマクロを使っている
フォームは字句上、マクロ定義の@code{let}の外側にあるからです。
@c COMMON
@c EN
We could rename @code{f}'s according to its lexical scope:
@c JP
@code{f}をレキシカルスコープによってリネームすれば次のようになるでしょう。
@c COMMON
@example
(let ([f_1 (^x (* x x))])
(let-macro ([m (^[expr1] `(let ([f_2 (^x (+ x x))]) (f_2 ,expr1)))])
(m (f_1 3))))
@end example
@c EN
Then expansion unambiguously distinguish two @code{f}'s.
@c JP
これだと展開しても二つの@code{f}はきちんと区別されます。
@c COMMON
@example
(let ([f_1 (^x (* x x))])
(let ([f_2 (^x (+ x x))])
(f_2 (f_1 3))))
@end example
@c EN
This is, in principle, what hygienic macro is about (well, almost).
In reality, we don't rename everything in batch.
One caveat is in the latter example---we statically renamed
@code{f} to @code{f_2}, but it is possible that the macro
recursively calls itself, and we have to distinguish @code{f}'s
introduced in every individual expansion of @code{m}.
So macro expansion and renaming should work together.
@c JP
以上が、衛生的マクロの原理です (まあ、だいたいは)。
ただし、実際の実装では、すべてを一気にリネームすることはありません。
後者の例のようなケースで注意すべき点があります。後者の例では静的に
@code{f}を@code{f_2}にリネームしましたが、より複雑な場合にマクロ展開器が
再帰的に自分を呼ぶことがあり、その場合にはマクロの展開ごとに挿入される@code{f}を
別のものとして扱う必要があります。
従って、マクロの展開とリネームは協調して動作しなければなりません。
@c COMMON
@c EN
There are multiple strategies to implement it, and the
Scheme standard doesn't want to bind implementations to single
specific strategy. The standard only states the properties
the macro system should satisfy, in two concise sentences:
@c JP
それを実装する戦略はいくつか考えられます。そして、Scheme標準は実装を
どれかひとつの戦略に縛ってしまうことを良しとしません。
結果的に、標準はマクロシステムが満たすべき性質を、二つの簡潔な
文で示すに止まります:
@c COMMON
@quotation
@c EN
If a macro transformer inserts a binding for an
identifier (variable or keyword), the identifier will in effect be
renamed throughout its scope to avoid conflicts with
other identifiers.
@c JP
マクロ展開器が識別子(変数かキーワード)の束縛を挿入した場合、
識別子はそのスコープ内で実効的にリネームされ、
他の識別子との衝突を避けられる。
@c COMMON
@c EN
If a macro transformer inserts a free reference to an
identifier, the reference refers to the binding that was
visible where the transformer was specified,
regardless of any local bindings that surround the use of the macro.
@c JP
マクロ展開器が識別子の自由参照を挿入した場合、その識別子は展開器が定義された場所から
見える束縛を参照し、マクロが使われる場所を囲むローカル束縛には影響されない。
@c COMMON
@end quotation
@c EN
Just from reading this,
it may not be obvious @emph{how} to realize those properties, and
the existing hygienic macro mechanisms (e.g. @code{syntax-rules}) hide
the ``how'' part. That's probably one of the reason some people
feel hygienic macros are difficult to grasp. It's like
continuations---its description is concise but at first
you have no idea how it works; then, through experience,
you become familiarized yourself to it, and then you reread
the original description and understand it says exactly what it is.
@c JP
これを読んだだけでは、これらの性質を@emph{いかにして}実現するかは
すぐにはわからないかもしれません。そして既存の衛生的マクロ(@code{syntax-rules}など)は
この@emph{いかにして}の部分を隠しています。それが、
衛生的マクロをとっつきにくく思う理由の一つかもしれません。
これはある意味、継続に似ています。継続の仕様はごく簡潔に述べられていて、
最初に読んだときにはどう動くかさっぱりわからないかもしれません。
しかし経験を積んで使うのに慣れた後でもう一度元の説明を読むと、
必要十分なことが書いてあるとわかるのです。
@c COMMON
@c EN
This introduction may not answer @emph{how} the hygienic macro
realizes those properties, but I hope it showed @emph{what} it does
and @emph{why} it is needed. In the following chapters we introduce
a couple of hygienic macro mechanisms Gauche supports, with examples,
so that you can familiarize yourself to the concept.
@c JP
この節では@emph{いかにして}衛生的マクロがこれらの性質を
実現しているかについての詳細には触れませんでしたが、
衛生的マクロが@emph{何を}して、@emph{何のために}必要かについて
ある程度示せたのではないかと思います。
以降の節では、Gaucheがサポートする衛生的マクロシステムについて
例を交え紹介してゆきます。
@c COMMON
@node Hygienic macros, Traditional macros, Why hygienic?, Macros
@section Hygienic macros
@c NODE 衛生的マクロ
@c EN
@subheading Macro bindings
@c JP
@subheading マクロ束縛
@c COMMON
@c EN
The following forms establish bindings of @var{name} and
a macro transformer created by @var{transformer-spec}. The
binding introduced by these forms shadows
a binding of @var{name} established in outer scope, if there's any.
@c JP
以下のフォームは@var{transformer-spec}で作られるマクロ変換器と
@var{name}の束縛を作ります。外側のスコープに@var{name}の束縛があれば、
それはシャドウされます。
@c COMMON
@c EN
For toplevel bindings, it will shadow bindings of @var{name} imported
or inherited from other modules (@pxref{Modules}).
(Note: This toplevel shadowing behavior is Gauche's extension;
in R7RS, you shouldn't redefine imported bindings, so the portable
code should avoid it.)
@c JP
トップレベル束縛の場合、@var{name}に他のモジュールからインポートされたり
継承されている束縛があれば、それをシャドウすることになります
(@ref{Modules}参照)。
(註:モジュール内でのトップレベル束縛がインポートした束縛をシャドウするのは
Gaucheの拡張です。R7RSではインポートした束縛の再定義はしてはいけないことに
なっているので、ポータブルなコードでは避けて下さい)。
@c COMMON
@c EN
The effect is undefined if you bind the same name more than once
in the same scope.
@c JP
同じスコープで同じ名前を複数回束縛した場合の動作は未定義です。
@c COMMON
@c EN
The @var{transformer-spec} can be either one of @code{syntax-rules}
form, @code{er-macro-transformer} form, or another macro keyword
or syntactic keyword. We'll explain them later.
@c JP
@var{transformer-spec}は@code{syntax-rules}フォーム、
@code{er-macro-transformer}フォーム、あるいは他のマクロキーワードか
構文キーワードです。これについては後述します。
@c COMMON
@defspec define-syntax name transformer-spec
[R7RS base]
@c EN
If this form appears in toplevel, it binds toplevel @var{name} to
a macro transformer defined by @var{transformer-spec}.
If this form appears in the @emph{declaration} part of
body of @code{lambda} (internal define-syntax), @code{let} and
other similar forms, it binds @var{name} locally within that body.
Conceptually, internal @code{define-syntax}es on the same level
are treated like @code{letrec-syntax}. However, mere appearance of
@code{define-syntax} does not create another scope; for example,
you can interleave internal @code{define} and internal @code{define-syntax}
within the same scope. It is important, though, that the local macros
defined by internal @code{define-syntax} should not be required
to expand macro uses before the definition.
@c JP
トップレベルで使われた場合、このフォームはトップレベルの@var{name}を
@var{transformer-spec}で定義されるマクロ変換器に束縛します。
@code{lambda}、@code{let}等の本体の宣言部分に使われた場合 (内部@code{define-syntax})、
その本体内のスコープで@var{name}を束縛します。
概念的には、同一階層にある内部@code{define-syntax}はまとめられて
@code{letrec-syntax}のように振る舞います。ただし、@code{define-syntax}が出てきたところで
新たなスコープが作られるわけではありません。
例えば内部@code{define}と内部@code{define-syntax}を一つのスコープ内で混ぜこせに
並べることができます。重要なのは、内部@code{define-syntax}で定義されるローカルマクロは、
その定義前にマクロ展開に必要とされてはならない、ということです。
@c COMMON
@end defspec
@defspec let-syntax ((name transformer-spec) @dots{}) body
@defspecx letrec-syntax ((name transformer-spec) @dots{}) body
[R7RS base]
@c EN
Defines local macros. Each @var{name} is bound to a macro
transformer as specified by the corresponding @var{transformer-spec},
then @code{body} is expanded. With @code{let-syntax},
@var{transformer-spec} is evaluated with the scope
surrounding @code{let-syntax}, while with @code{letrec-syntax}
the bindings of @var{name}s are included in the scope where
@var{transformer-spec} is evaluated. Thus @code{letrec-syntax}
allows mutually recursive macros.
@c JP
ローカルマクロを定義します。各@var{name}が
対応する@var{transformer-spec}で定義されるマクロ変換器へと束縛された
環境を作り@var{body}を評価します。
@code{let-syntax}では、@var{transformer-spec}は@code{let-syntax}を
囲むスコープ内で@var{transformer-spec}を評価するのに対し、
@code{letrec-syntax}では@var{name}の束縛がなされた環境で
@var{transformer-spec}を評価します。つまり@code{letrec-syntax}は
相互再帰的なマクロを定義できます。
@c COMMON
@end defspec
@subheading Transformer specs
@c EN
The @var{transformer-spec} is a special expression that evaluates
to a macro transformer. It is evaluated in a different phase
than the other expressions, since macro transformers must be
executed during compiling. So there are some restrictions.
At this moment, only one of the following expressions are allowed:
@c JP
@var{transformer-spec}は、マクロ展開器へと評価される特別な式です。
マクロ変換器はコンパイル時に実行されるため、他の式とは異なった段階で評価されます。
そのためにいくらか制限があります。
現在のところ、以下に挙げる式しか許されていません。
@c COMMON
@enumerate
@item
@c EN
A @code{syntax-rules} form. This is called ``high-level'' macro,
for it uses pattern matching entirely, which is basically a
different declarative language from Scheme, thus putting the
complication of the phasing and hygiene issues completely under the hood.
Some kind of macros are easier to write in @code{syntax-rules}.
@xref{Syntax-rules macro transformer}, for further description.
@c JP
@code{syntax-rules}フォーム。これは「高レベル」マクロと呼ばれ、
パターンマッチングのみによってマクロを定義します。
これはSchemeとは異なる一種の宣言的言語で、
マクロの段階や衛生の問題をボンネットの下に隠してしまいます。
ある種のマクロは@code{syntax-rules}でより簡単に書けます。
詳しくは@ref{Syntax-rules macro transformer}を参照してください。
@c COMMON
@item
@c EN
An @code{er-macro-transformer} form. This employs @emph{explicit-renaming}
(ER) macro, where you can use arbitrary Scheme code to transform
the program, with required renaming to keep hygienity. The legacy
Lisp macro can also be written with ER macro if you don't use
renaming. @xref{Explicit-renaming macro transformer}, for the details.
@c JP
@code{er-macro-transfomer}フォーム。
これは@emph{explicit renaming}(ER)マクロを定義します。
ERマクロでは、必要な衛生を保ちながら、任意のSchemeコードを使って変換を書けます。
伝統的なLispのマクロは、ERマクロでリネームを使わない特別な場合と考えられます。
詳しくは@ref{Explicit-renaming macro transformer}を参照してください。
@c COMMON
@item
@c EN
A @code{make-id-transformer} form. This creates an @emph{identifier macro},
Unlike an ordinary macro, an identifier macro expands without
being at the head of a list; it looks like a variable in the source.
@xref{Identifier transformer}, for the details.
@c JP
@code{make-id-transformer}フォーム。
これは@emph{識別子マクロ}を定義します。
通常のマクロと異なり、識別子マクロはリストの最初の位置に置かれないでも展開されます。
ソース上では通常の変数のように見えます。
詳しくは@ref{Identifier transformer}を参照してください。
@c COMMON
@item
@c EN
Macro or syntax keyword. This is Gauche's extension, and can be
used to define alias of existing macro or syntax keyword.
@c JP
マクロキーワードか構文キーワード。これはGauche独自の拡張で、
既存のマクロキーワードや構文キーワードの別名を定義するものです。
@c COMMON
@example
(define-syntax si if)
(define écrivez write)
(si (< 2 3) (écrivez "oui"))
@end example
@end enumerate
@menu
* Syntax-rules macro transformer::
* Explicit-renaming macro transformer::
* Identifier transformer::
@end menu
@node Syntax-rules macro transformer, Explicit-renaming macro transformer, Hygienic macros, Hygienic macros
@subsection Syntax-rules macro transformer
@c NODE Syntax-rulesマクロ変換器
@defspec syntax-rules (literal @dots{}) clause clause2 @dots{}
@defspecx syntax-rules ellipsis (literal @dots{}) clause clause2 @dots{}
[R7RS base]
@c EN
This form creates a macro transformer by pattern matching.
Each @var{clause} has the following form:
@c JP
パターンマッチングによるマクロ変換器を作ります。
各@var{clause}は次の形式です。
@c COMMON
@example
(@var{pattern} @var{template})
@end example
@c EN
A @var{pattern} denotes a pattern to be matched to the macro call.
It is an S-expression that matches if the macro call has the same
structure, except that symbols in @var{pattern} can match a whole subtree
of the input; the matched symbol is called a @emph{pattern variable},
and can be referenced in the @var{template}.
@c JP
@var{pattern}はマクロ呼び出しにマッチすべきパターンを記述します。
パターンはS式で、マクロ呼び出しの式と同じ構造を持っている場合にマッチします。
但し、パターン中のシンボルは@emph{パターン変数}と呼ばれ、
マクロ呼び出し式の対応する任意の部分木とマッチし、
@var{template}の中でマッチした部分木を参照するのに使えます。
@c COMMON
@c EN
For example, if a pattern is @code{(_ "foo" (a b))}, it can match the
macro call @code{(x "foo" (1 2))}, or @code{(x "foo" (1 (2 3)))}, but does
not match @code{(x "bar" (1 2))}, @code{(x "foo" (1))} or
@code{(x "foo" (1 2) 3)}. You can also match repeating structure or
literal symbols; we'll discuss it fully later.
@c JP
例えば、パターンが@code{(_ "foo" (a b))}であったとすると、それは
@code{(x "foo" (1 2))}や@code{(x "foo" (1 (2 3)))}といったマクロ呼び出しとマッチしますが、
@code{(x "bar" (1 2))}、@code{(x "foo" (1))}、@code{(x "foo" (1 2) 3)}とは
マッチしません。
さらに、後で説明するように、繰り返しのある構造やリテラルシンボルとマッチするような記述も可能です。
@c COMMON
@c EN
Clauses are examined in order to see if the macro call form matches
its pattern. If matching pattern is found, the corresponding @var{template}
replaces the macro call form. A pattern variable in the template is
replaced with the subtree of input that is bound to the pattern variable.
@c JP
@var{clause}は順番に、そのパターンにマクロ呼び出しとマッチするかが検査されます。
マッチするパターンが見つかれば、対応する@var{template}でマクロ呼び出しの式が
置き換えられます。@var{template}中のパターン変数は、
マクロ呼び出し式のその変数にマッチした部分木で置き換えられます。
@c COMMON
@c EN
Here's a definition of @code{when} macro in @ref{Why hygienic?},
using @code{syntax-rules}:
@c JP
これは@ref{Why hygienic?}で例に出した@code{when}マクロを
@code{syntax-rules}で書いたものです:
@c COMMON
@example
(define-syntax when
(syntax-rules ()
[(_ test body ...) (if test (begin body ...))]))
@end example
@c EN
The pattern is @code{(_ test body ...)}, and the template is
@code{(if test (begin body ...))}.
The ellipsis @code{...} is a symbol; we're not omitting code here.
It denotes that the previous pattern (@code{body}) may
repeat zero or more times.
@c JP
パターンが@code{(_ test body ...)}で、
テンプレートが@code{(if test (begin body ...))}です。
@code{...} (エリプシス) は、記述を省略しているわけではなく、
ピリオド3つからなる名前を持つシンボルです。
これは直前のパターン(@code{body})がゼロ個以上繰り替えされるということを示します。
@c COMMON
@c EN
So, if the @code{when} macro is called as
@code{(when (zero? x) (print "huh?") (print "we got zero!"))},
the macro expander first check if the input matches the pattern.
@c JP
@code{when}マクロが
@code{(when (zero? x) (print "huh?") (print "we got zero!"))}
という形で呼び出されたとしましょう。
マクロ展開器はまず、この入力がパターンとマッチするかどうかを調べます。
@c COMMON
@itemize @bullet
@item
@c EN
The @var{test} in pattern matches the input @code{(zero? x)}.
@c JP
パターン中の@var{test}は入力の@code{(zero? x)}とマッチ。
@c COMMON
@item
@c EN
The @var{body} in pattern matches the input @code{(print "huh?")}
@emph{and} @code{(print "we got zero!")}.
@c JP
パターン中の@var{body}は入力の@code{(print "huh?")}および@code{(print "we got zero!")}とマッチ
@c COMMON
@end itemize
@c EN
The matching of @var{body} is a bit tricky; as a pattern variable,
you may think that @var{body} works like an array variable, each element
holds each match---and you can use them in similarly
repeating substructures in template.
Let's see the template, now that the input fully matched the pattern.
@c JP
@var{body}とのマッチングはちょっとややこしいです。
パターン変数@var{body}は配列のようなものだと考えても良いでしょう。
配列の各要素がマッチする入力の部分木を保持します。
その値は、テンプレート中の似たような繰り返し部分構造の中で使うことができます。
ここまでで入力がパターンにマッチしたので、テンプレートの方を見てみましょう。
@c COMMON
@itemize @bullet
@item
@c EN
In the template, @code{if} and @code{begin} are not pattern variable,
since they are not appeared in the pattern.
So they are inserted as identifiers---that is, hygienic symbols effectively
renamed to make sure to refer to the global @code{if} and @code{begin},
and will be unaffected by the macro use environment.
@c JP
テンプレート中の@code{if}と@code{begin}はパターン中に現れていないので
パターン変数ではありません。従って、識別子として出力に挿入されます。
ここで、識別子@code{if}や@code{begin}はこのマクロのスコープから見えるグローバルな
@code{if}や@code{begin}を常に参照できるように、衛生的に扱われます。
マクロが使われた場所で@code{if}や@code{begin}がシャドウされていたとしても影響を受けません。
@c COMMON
@item
@c EN
The @var{test} in the template is a pattern variable, so it is replaced
for the matched value, @code{(zero? x)}.
@c JP
テンプレート中の@var{test}はパターン変数なので、マッチした値である@code{(zero? x)}へと
置き換えられます。
@c COMMON
@item
@c EN
The @var{body} is also a pattern variable. The important point is
that it is also followed by ellipsis. So we repeat @var{body} as many
times as the number of matched values.
The first value, @code{(print "huh?")}, and the second value,
@code{(print "we got zero!")}, are expanded here.
@c JP
@var{body}もパターン変数です。重要な点はここでも@var{body}の後にエリプシスがあることで、
@var{body}はパターン変数にマッチした値のぶんだけ繰り返されます。
最初のマッチした値である@code{(print "huh?")}と、次の
@code{(print "we got zero!")}とがここに展開されます。
@c COMMON
@item
@c EN
Hence, we get
@code{(if (zero? x) (begin (print "huh?") (print "we got zero!")))}
as the result of expansion. (With the note that @code{if} and @code{begin}
refers to the identifiers visible from the macro definition environment.)
@c JP
以上から、最終的な展開結果として
@code{(if (zero? x) (begin (print "huh?") (print "we got zero!")))}
が得られます (このうち、@code{if}と@code{begin}は
マクロ定義環境から見える識別子を指すようになっています)。
@c COMMON
@end itemize
@c EN
The expansion of ellipses is quite powerful. In the template,
the ellipses don't need to follow the sequence-valued pattern variable
immediately; the variable can be in a substructure, as long as the
substructure itself is followed by an ellipsis.
See the following example:
@c JP
エリプシスを使った展開はかなり強力です。
テンプレート中で、エリプシスは複数の値を持つパターン変数の直後にある必要はありません。
そういった変数を中に含む部分構造をエリプシスで繰り返すことも可能です。
次の例を見てください。
@c COMMON
@example
(define-syntax show
(syntax-rules ()
[(_ expr ...)
(begin
(begin (write 'expr) (display "=") (write expr) (newline))
...)]))
@end example
@c EN
If you call this macro as follows:
@c JP
このマクロを次のように呼ぶと:
@c COMMON
@example
(show (+ 1 2) (/ 3 4))
@end example
@c EN
It is expanded to the following form, modulo hygienity:
@c JP
以下のとおりに展開されます (シンボルの衛生性は保たれているとします)。
@c COMMON
@example
(begin
(begin (write '(+ 1 2)) (display "=") (write (+ 1 2)) (newline))
(begin (write '(/ 3 4)) (display "=") (write (/ 3 4)) (newline)))
@end example
@c EN
So you'll get this output.
@c JP
これを実行すれば、以下の出力が得られるでしょう。
@c COMMON
@example
(+ 1 2)=3
(/ 3 4)=3/4
@end example
@c EN
You can also match with a repetition of substructures in the pattern.
The following example is a simplified @code{let} that expands to
@code{lambda}:
@c JP
また、パターン中の部分構造を繰り返しマッチするのにも使えます。
次の例は@code{let}を@code{lambda}に展開する、簡略化した例です:
@c COMMON
@example
(define-syntax my-let
(syntax-rules ()
[(_ ((var init) ...) body ...)
((lambda (var ...) body ...) init ...)]))
@end example
@c EN
If you call it as @code{(my-let ((a expr1) (b expr2)) foo)},
then @var{var} is matched to @code{a} and @code{b},
while @var{init} is matched to @code{expr1} and @code{expr2}, respectively.
They can be used separately in the template.
@c JP
このマクロを@code{(my-let ((a expr1) (b expr2)) foo)}のように呼び出すと、
@var{var}は@code{a}および@code{b}に、
@var{init}は@code{expr1}および@code{expr2}にそれぞれマッチします。
@var{var}と@var{init}はテンプレート中でばらばらに使うことができます。
@c COMMON
@c EN
Suppose ``level'' of a pattern variable
means the number of nested ellipses that designate repetition of the pattern
variable.
A subtemplate can be followed as many ellipses as the maximum level of
pattern variables in the subtemplate.
In the following example, the level of pattern variable @code{a} is 1
(it is repeated by the last ellipsis in the pattern),
while the level of @code{b} is 2 (repeated by the last two ellipses),
and the level of @code{c} is 3 (repeated by all the ellipses).
@c JP
パターン変数の繰り返しを示すエリプシスの入れ子の数を、
そのパターン変数のレベルと呼ぶことにします。
サブテンプレートは、その中に含まれるパターン変数のレベルの最大値と同じだけの
エリプシスの入れ子に中になければなりません。
次の例では、パターン変数@code{a}のレベルは1 (最後のエリプシスによって繰り返される)、
@code{b}は2 (後ろの2つのエリプシスで繰り返される)、
@code{c}は3 (全てのエリプシスで繰り返される) です。
@c COMMON
@example
(define-syntax ellipsis-test
(syntax-rules ()
[(_ (a (b c ...) ...) ...)
'((a ...)
(((a b) ...) ...)
((((a b c) ...) ...) ...))]))
@end example
@c EN
In this case, the subtemplate @code{a} must be repeated by one level
of ellipsis, @code{(a b)} must be repeated by two,
and @code{(a b c)} must be repeated by three.
@c JP
したがって、サブテンプレート @code{a} は1重、
サブテンプレート @code{(a b)}は2重、
@code{(a b c)}は3重のエリプシスで繰り返されることになります。
@c COMMON
@example
(ellipsis-test (1 (2 3 4) (5 6)) (7 (8 9 10 11)))
@result{} ((1 7)
(((1 2) (1 5)) ((7 8)))
((((1 2 3) (1 2 4)) ((1 5 6))) (((7 8 9) (7 8 10) (7 8 11)))))
@end example
@c EN
In the template, more than one ellipsis directly follow a subtemplate,
splicing the leaves into the surrounding list:
@c JP