LoginSignup
3
1

More than 5 years have passed since last update.

フォームの継ぎ合わせ

Posted at

ふたつの begin

プログラミング言語 Scheme の中で比較的頻繁に現れる構文として begin がある。 複数の式をひとつにまとめる構文で、おそらくは if と共に使う場合が多いのではないだろうか。

(if foo
    (begin (display "Hello, world") (newline)))

R5RS だとちょっとあやふやでわかり難いのだが、 R6RS と R7RS では begin は二種類あることが明記されている。 begin を使用する場所によって意味が切り替わるのだ。

  • 上述の例のように、通常の式として表われる場合
  • <body> 部やトップレベルなどに表われる場合

単純に複数の式をひとつにまとめるのはわかりやすい例で、 C などの文法で言うところの { } と同じような感覚だろう。

begin の継ぎ合わせ

特殊な動作をするのは <body> 部やトップレベルなどに現われた場合だ。 <body> 部の詳細な定義はここでは述べないが、たとえば lambda 構文で引数の次の場所はそのひとつだ。

(lambda <formals> <body>)

<body> 部に現れる begin は上位フォームへの継ぎ合わせ (splicing) がおこなわれる。

つまり、たとえば

(lambda ()
  (display "Hello,")
  (begin (display "World")
         (newline)))

という式があった場合、 begin の内側はその外側にあるのと同じようにふるまうので、

(lambda ()
  (display "Hello,")
  (display "World")
  (newline))

と同じことになる。 要するに、 begin で囲まないのと同じだということだ。

begin の継ぎ合わせが必要な理由

あってもなくても同じならどういうときに使うのかと思うかもしれない。 それは主にマクロのためだ。 マクロはひとつの式をひとつの式に変換するが、出力結果を複数の式にしたいこともある。 そういったときに見掛け上をひとつの式にするために begin でくるむのである。

たとえば、同じ値に束縛をたくさん作りたいようなことがあったとき、

(define a 0)
(define b 0)
(define c 0)

という風に並べるのは面倒であるから、一度に指定できるようなマクロを作ろうとするとこうなる。

(define-syntax define-zero
  (syntax-rules ()
    ((_ id ...)
     (begin (define id 0) ...))))

(define-zero a b c) ;; 使用例
(display a) ;; a は 0 に束縛されている

もしも、このときに begin が C などの { } と同じようにスコープを形成してしまうのだと、マクロで定義系の構文を生成するのは強い制限がかかることになってしまう。 begin が上位フォームに継ぎ合わされる (実質的に begin囲まないのと同じになる) という、一見して奇妙にも思える規則はこうして有用に役立てられるのである。

let-syntaxletrec-syntax の継ぎ合わせ

継ぎ合わせが起こるのは begin だけではない。 R6RS の let-syntaxletrec-syntax もそうだ。 ただ、 R5RS や R7RS ではこれらの構文では継ぎ合わせは起こらないという違いがある。

このような式を書いた場合、

(let ((foo 'a))
  (let-syntax ()
    (define foo 'b)
    'dummy-for-r7rs)
  foo)

R6RS では 'b になるが、 R5RS や R7RS では 'a となるという違いになって現われる。

とても地味な違いだが、()ったマクロを考えるときには R6RS の方がやりやすいと私は感じている。 継ぎ合わせをしてくれる場合には継ぎ合わせが起こって欲しくない箇所を適当に let でくるめば済むが、継ぎ合わせが起こらない分には継ぎ合わせを引き起こすことは出来ないので使い分けられないからだ。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1