ループを記述する


Tags: R6RS, 手続き, 制御構造

Scheme では末尾呼び出しの最適化が行なわれるため、ループはすべて手続きの末尾呼び出しとして記述される。例えば次のようなループ

int i;

for (i = 0; i < 10; i++) {
    ...
}

は Scheme では

(import (rnrs))

(define (for from to proc)
  (cond ((< from to)
         (proc from)
         (for (+ from 1) to proc))))

(for 0 10 (lambda (i) ...))

と記述するか、あるいは内部定義や局所束縛を使い

(import (rnrs))

(define (foo)
  (define (for from to proc)
    (cond ((< from to)
           (proc from)
           (for (+ from 1) to proc))))
  (for 0 10 (lambda (i) ...)))

(import (rnrs))

(letrec ((for (lambda (from to proc)
                (cond ((< from to)
                       (proc from)
                       (for (+ from 1) to proc))))))
  (for 0 10 (lambda (i) ...)))

と記述する。これらのような記述は頻出するので、名前付き let という繰り返しを記述するのに便利な構文が用意されている。

(import (rnrs))

(let for ((i 0))
  (cond ((< i 10)
         ...
         (for (+ i 1)))))

これは letrec を使った記述とおよそ同等である。

また典型的な繰り返しには do 構文が利用できる。

(import (rnrs))

(do ((i 0 (+ i 1)))
    ((>= i 10))
  ...)

さらに、リスト文字列ベクタ上の繰り返しには for-each, string-for-each, vector-for-each が用意されている。これらもまた最終的には手続きの末尾呼び出しに変形される。