ループから脱出する


Tags: R6RS, 手続き

リストの中から特定の述語を満足する値を見つける手続きを考える。これを一般の言語で考えると

  1. リストの各要素についてループする
  2. 述語を満たす要素を見つけたらループを打ち切り、その要素を返す
  3. さもなくはループを繰り返す
  4. リストの終端に辿りついた場合は適当な値を返す

ここでは、リストの終端に辿りついた場合 #f を返すものとする。リストの要素に関する繰り返しは for-each で実現でき、打ち切りは call/cc で実現できる。

(import (rnrs))

(define (f pred? xs)
  (call/cc
   (lambda (break)
     (for-each
      (lambda (x)
        (when (pred? x)
          (break x)))
      xs)
     #f)))

ところで、 Scheme ではループは末尾位置における手続き呼び出しで実現されているため、ループの打ち切りは煎じ詰めれば単純にループ手続きを呼び出さないことに一致する。

(import (rnrs))

(define (f pred? xs)
  (let loop ((xs xs))
    (cond ((null? xs)
           #f)
          ((pred? (car xs))
           (car xs))
          (else
           (loop (cdr xs))))))

そもそも求める手続きの動作は (rnrs lists) の find 手続きと同一である。

(import (rnrs))

(define f find)

一般に Scheme ではループから脱出するための特定の構文が必要になることは少ない。