util.stream
- ストリームライブラリ ¶このモジュールは遅延ストリームのライブラリを提供します。このモジュール
にはSRFI-40とSRFI-41で定義されている関数および構文が含まれています。
後者は(scheme stream)
としてR7RS largeの一部になっています。
Gaucheには遅延ストリームとリストを統合したような、組み込みの遅延シーケンスがあります (遅延シーケンス)参照。そちらは通常のリスト手続きを使って扱うことができます。 このモジュールで提供される遅延ストームは、遅延シーケンスより重く、 扱うために専用の手続きが必要です。ただ、要素の評価は必要になるぎりぎりまで遅延され (遅延シーケンスでは必要な要素のひとつ先まで評価されます)、またポータブルです。
• Stream primitives: | ||
• Stream constructors: | ||
• Stream binding: | ||
• Stream consumers: | ||
• Stream operations: |
[R7RS stream]
{util.stream
}
objがutil.stream
の手続きによって作成されたストリームであ
る場合にかぎり#t
を返します。
[R7RS stream]
{util.stream
}
NULLストリームのシングルトンインスタンス。
[R7RS stream]
{util.stream
}
ストリームの基本構成子。objectをstreamの先頭に追加し、新し
いストリームを返します。
[R7RS stream]
{util.stream
}
objがNULLストリームの場合にのみ#t
を返します。
[R7RS stream]
{util.stream
}
objがNULLストリームではないストリームのときにのみ#t
を返します。
[R7RS stream]
{util.stream
}
ストリームsの最初の要素を返します。
[R7RS stream]
{util.stream
}
ストリームsの最初の要素を除いた残りの要素をストリームとして
返します。
[SRFI-40]{util.stream
}
exprの遅延形式であるストリームを返します。
原則として、ストリームを生成する関数はすべからく結果を
stream-delay
でラップすべきです。
(以下に述べるstream-lambda
, stream-let
, stream-define
を
使う手もあります)。
[R7RS stream]
{util.stream
}
ストリームを返す関数を作る簡易マクロです。
(stream-lambda formals body body2 …)
は
(lambda formals (stream-delay body body2 …))
と同じです。
[SRFI-40]{util.stream
}
要素がobj …であるような新しいストリームを返します。
註:これはSRFI-41 (scheme.stream
)のstream
とは異なります。
SRFI-41の方はマクロで、引数の評価が遅延されます。SRFI-41版はこのモジュールでは
stream+
と言う名前で提供されます。
(stream 1 2 3)) ⇒ a stream that contains (1 2 3) (stream 1 (/ 1 0))) ⇒ error
{util.stream
}
要素がexpr …の結果であるような新たなストリームを作って返します。
これはSRFI-41(scheme.stream
)のstream
と同じです。
各exprはアクセスされるまで評価されません。
(define s (stream+ 1 (/ 1 0))) ;; doesn't yield an error
(stream-car s) ⇒ 1
(stream-cadr s) ⇒ error
[R7RS stream]
{util.stream
}
次の手順で生成される要素をもつ新たなストリームを作成して返します。
#f
が返されたら、ストリームはそこで終了です。
s
を現在のシード値として、(f s)
をストリームの
現在の要素とし、(g s)
を次のシード値とします。
seedはシード値の初期値を与えます。
註:残念なことに、この手続きは他の *-unfold
系手続きと異なる順序で
引数を取ります。他の手続きはp f g
(述語、値生成、シード生成) の順です。
さらに、他の手続きでは述語は停止する時に真を返します。
(stream->list (stream-unfold integer->char (cut < <> 58) (cut + 1 <>) 48)) ⇒ (#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
[SRFI-40]{util.stream
}
互いに関連する n 本のストリームを生成します。それぞれの内容は
fおよびseedを使って生成します。
fは現在のシード値とともに呼ばれ、n+1
個の値
を返します。
(f seed) => seed result_0 result_1 ... result_n-1
最初の値は次のシード値になります。Result_kは以下の形式のどれかで なければなりません。
(val)
valはk-番目のストリームの次のcar部になります。
#f
k-番目のストリームの新しい情報はありません。
()
k-番目のストリームの最後に到達しました。
以下の例では2つのストリームが作られます。最初のものは奇数の無限ストリー ムで、2つめのものは偶数の無限ストリームです。
gosh> (define-values (s0 s1) (stream-unfoldn (lambda (i) (values (+ i 2) ;; next seed (list i) ;; for the first stream (list (+ i 1)))) ;; for the second stream 0 2)) #<undef> gosh> (stream->list (stream-take s0 10)) (0 2 4 6 8 10 12 14 16 18) gosh> (stream->list (stream-take s1 10)) (1 3 5 7 9 11 13 15 17 19)
[R7RS stream]
{util.stream
}
stream-unfoldn
と似ていますが、結果のストリームの数は
fの戻り値の数により決定されます。詳しくは
上のstream-unfoldn
の説明を参照してください。
[R7RS stream]
{util.stream
}
obj …を繰り返す無限ストリームを返します。
(stream->list 10 (stream-constant 1 2)) ⇒ (1 2 1 2 1 2 1 2 1 2)
{util.stream
}
n個のinitを要素とする新しいストリームを生成します。
initが省略された場合#f
が使われます。nを負の値にする
と無限ストリームが生成されます。
{util.stream
}
n個の要素をもつ新しいストリームを生成します。k-番目の要素
は init-proc を k に適用して得られます。nを負の値にする
と無限ストリームが生成されます。
{util.stream
}
startからはじまり、stepずつ要素が増加する数値のストリーム
を生成します。ストリームの長さは非負の実数countを越えない最大の整数値です。
count, start, stepのデフォルト値はそれぞれ
+inf.0
, 0 および 1です。
startとstepが正確数で、countが正確数か無限大の場合、 正確数のストリームが作られます。そうでなければ非正確数のストリームになります。
[R7RS stream]
{util.stream
}
startから始まりstepおきにendの手前まで続く実数のストリームを
作って返します。endが省略された場合は正の無限大が使われます。
stepが省略された場合、startがendより小さければ1
が、
大きければ-1が使われます。
startとstepが正確数で、endが正確数か無限大の場合は、 正確数のシーケンスが、そうでない場合は非正確数のシーケンスが生成されます。
R7RSのscheme.stream
では、end引数は必須です。
(stream->list (stream-range 0 10)) ⇒ (0 1 2 3 4 5 6 7 8 9)
[R7RS stream]
{util.stream
}
もうひとつの数値シーケンス生成手続きです。i番目の項が
(+ start (* i step))
であるような無限シーケンスを返します。
stepが省略されたら1が使われます。
startとstepが正確数なら、正確数のシーケンスが、
そうでなければ非正確数のシーケンスが返されます。
[R7RS stream]
{util.stream
}
seedを初期値とし、ひとつ前の要素sから次の要素を(f s)
で
計算するような無限長のストリームを返します。
(stream->list 5 (stream-iterate (cut cons 'x <>) '())) ⇒ (() (x) (x x) (x x x) (x x x x))
gauche.lazy
のliterate
も参照
(gauche.lazy
- 遅延シーケンスユーティリティ).
{util.stream
}
(stream-cons b a)
のこと。利便性のためだけにある。
{util.stream
}
streamの前にelt …を連結した新しいストリームを生成し
ます。
[R7RS stream]
{util.stream
}
listの要素を要素とする新たなストリームを作って返します。
{util.stream
}
文字列を文字のストリームに変換します。tail-streamが与えられた場合は、
文字ストリームの後にそれが付け加えられます。
(stream->list (string->stream "abc" (list->stream ’(1 2 3)))) ⇒ (#\a #\b #\c 1 2 3)
{util.stream
}
string->stream
を(format fmt arg …)
に適用した結果の
ストリームを返します。
[R7RS stream]
{util.stream
}
iportからreaderを使って読み出されるデータを要素とする新たなストリームを
作って返します。iportのデフォルトは現在の入力ポート、
readerのデフォルトはread-char
です。
readerがEOFを返したらストリームの終端となります (EOF自体は ストリームには含まれません)。 EOFに達してもポートはクローズされません。
もしcloser引数が与えられたら、それがiportを引数として EOFが読まれた直後に呼ばれます。そこでポートをクローズするこはできます。
readerとcloser引数はR7RSのscheme.stream
では
定義されない、Gaucheの拡張です。
{util.stream
}
ジェネレータgenが生成する値の列からなる遅延ストリームを作って返します。
ジェネレータは引数を取らない手続きで、呼ばれる度に値を返し、EOFを返すことで
終端を示すものです(EOFはストリームには含まれません)。
詳しくはgauche.generator
- ジェネレータを参照してください。
似た手続きに、ジェネレータから遅延シーケンスを得るgenerator->lseq
も
あります(遅延シーケンス参照)。
{util.stream
}
イテレータiterから遅延シーケンスを作る手続きです。
iterは二つの引数nextとendを取る手続きです。 nextは一つの引数を取る手続き、endは引数を取らない手続きです。 iter手続きは、その中で何らかの値の集合に対して順にnext手続きを呼び、 最後にend手続きを呼びます。次はわざとらしい例です:
(stream->list (iterator->stream (lambda (next end) (for-each next '(1 2 3 4 5)) (end)))) ⇒ (1 2 3 4 5)
内部的に、iterator->stream
はいわゆる「イテレータの反転」テクニックを
使っていて、iterは必要なだけしかイテレーションを行いません。なので
iterは無限の要素を扱うこともできます。
例えば次の例では、iterは増加する整数に対してnextを無限に呼び出す
ようになっていますが、stream-take
によって最初の10要素しか計算されません。
(stream->list (stream-take (iterator->stream (lambda (next end) (let loop ((n 0)) (next n) (loop (+ n 1))))) 10)) ⇒ (0 1 2 3 4 5 6 7 8 9)
[R7RS stream]
{util.stream
}
ストリーム内包表記。各要素がelt-exprで計算されるストリームを返します。
clauseはelt-exprのスコープを作り、繰り返しを制御します。
各clauseは以下の形のいずれかです:
(x in stream-expr)
stream-exprが返すストリームの各要素を、xに束縛して繰り返します。 変数xのスコープは後続のclauseおよびelt-exprです。
(x is expr)
変数xに値exprの結果を束縛します。xのスコープは 後続のclauseおよびelt-exprです。
expr
exprが#f
に評価されたらこの回は値を生成せずに打ちきられ、
次の繰り返しに進みます。
次の内包表記はピタゴラス数の無限シーケンスを生成します:
(define pythagorean-triples (stream-of (list a b c) (c in (stream-from 3)) (b in (stream-range 2 c)) (a in (stream-range 1 b)) (= (square c) (+ (square b) (square a))))) (stream->list 5 pythagorean-triples) ⇒ ((3 4 5) (6 8 10) (5 12 13) (9 12 15) (8 15 17))
[R7RS stream]
{util.stream
}
ストリームを作って返す関数を手軽に定義するマクロです。
次のフォームと同じです:
(define (name . formals) (stream-delay (let () body body2 ...)))
[R7RS stream]
{util.stream
}
lazyなnamed-letによるループを書くときに便利なマクロです。次のフォームと同じです:
(let loop-var ((var init) ...) (stream-delay (let () body body2 ...)))
[R7RS stream]
{util.stream
}
このマクロは簡単なパターンマッチングを使ってストリームの要素にアクセスします。
stream-exprはストリームを返す式でなければなりません。
各clauseは(pattern expr)
か
(pattern fender expr)
という形です。
入力ストリームは各patternに順マッチするかどうかテストされます。 patternには以下の形のいずれかです:
()
空のストリームとマッチします。
(p0 p1 …)
パターン内の要素の数と入力ストリームの要素数が一致した時にマッチします。
(p0 p1 … . pRest)
入力ストリームの要素数が、pRestを除いたパターン内の要素の数以上であれば マッチします。pRestにはストリームの残りがマッチします。
pRest
入力ストリーム全体とマッチします。
パターンの各要素は識別子かリテラルのアンダースコア_
です。
アンダースコア以外の識別子の場合は、それらが対応する入力ストリームの要素に
束縛された環境でfenderとexprが評価されます。
もしfenderがあれば、まずそれが評価され、#f
であったらそのclauseの
マッチは失敗となり、次のclauseが試されます。
そうでなければexprが評価され、その結果がstream-match
の結果となります。
入力ストリームの要素はマッチに必要なだけ取り出されます。
次の例は、ストリーム中の真の値の数を数えています:
(define (num-trues strm) (stream-match strm (() 0) ((head . tail) head (+ 1 (num-trues tail))) ((_ . tail) (num-trues tail)))) (num-trues (stream #f #f #t #f #t #f #t #t)) ⇒ 4
これらの手続きはストリームを取り、その要素を消費し尽します。
[R7RS stream]
{util.stream
}
funcをstreamsの各要素に適用します。
streamsが終端に達したところで停止します。
[R7RS stream]
{util.stream
}
fを現在のシード値とstreamの要素に適用し、その結果を次のシード値として
streamが終端に達するまで繰り返します。最初のシード値はseed引数で与えられます。
最後のシード値が返されます。
註: fの引数順は、他の*-fold
系関数のそれと異なることに注意してください。
例えばfold
(リストをたどる手続き参照) では最初に要素、次にシード値が
渡されます。
(stream-fold - 0 (stream 1 2 3 4 5)) ⇒ -15
[R7RS stream]
{util.stream
}
与えられたstreamを全部つないだ新たなストリームを返します。
[R7RS stream]
{util.stream
}
R7RS scheme.stream
はstream-concat
を定義しました。
Gaucheにはstream-concatenate
があったので互換性のためにそちらも残しています。
どちらも同じです。
streamsはストリームのストリームです。各ストリームを連結したストリームを作って
返します。stream-append
と違い、streamsは無限個のストリームを生成
することができます。
[R7RS stream]
{util.stream
}
streamsの各要素にfuncを適用した値を要素とする新しいストリー
ムを返します。
[R7RS stream]
{util.stream
}
seed
、
(func seed e0)
、
(func (func seed e0) e1)
…
で構成されるストリームを返します。ここで
e0、e1 …は入力ストリームstreamの要素です。
streamが有限なら、その要素よりひとつ多い要素が出力ストリームには含まれます。
(stream->list (stream-scan xcons '() (stream 1 2 3 4 5))) ⇒ (() (1) (2 1) (3 2 1) (4 3 2 1) (5 4 3 2 1))
[R7RS stream]
{util.stream
}
入力ストリームの対応する要素のリストを要素とするストリームを作って返します。
入力ストリームのいずれかが終端に達した時に出力ストリームも終わります。
(stream->list (stream-zip (stream 1 2 3) (stream 'a 'b 'c 'd))) ⇒ ((1 a) (2 b) (3 c))
[R7RS stream]
{util.stream
}
predをパスする要素のみからなる新しいストリームを返します。
この手続きは直ちに返ります。streamは無限ストリームであっても構いません。
{util.stream
}
述語predを満たさない要素のみからなる新しいストリームを返します。
(stream-filter (complement pred) stream)
と同じです。
{util.stream
}
二つのストリームを返します。最初のストリームはstreamの要素のうち
述語predを満たすもの、次のストリームはpredを満たさないもので構成されます。
[R7RS stream]
{util.stream
}
ストリームをリストに変換します。最初の形式では、streamの全ての要素が
取り出されます (従ってstreamが無限ストリームであればこの関数は永遠に戻りません)。
二番めの形式では最大でn要素までがストリームから取り出されそのリストが返されます。
nは非負の正確な整数でなければなりません。
註:通常のSchemeの慣例では、省略可能なnはstreamの後に来ますが、 この関数はそうでないことに注意。
{util.stream
}
ストリームを文字列に変換します。
streamの全ての要素は文字でなければなりません。
そうでない場合はエラーが投げられます。
{util.stream
}
streamを、文字#\n
が要素である箇所で分割し、
分割されたストリームのストリームを返します。#\n
自体は結果に含まれません。
(stream->list (stream-map stream->string (stream-lines (string->stream "abc\ndef\nghi")))) ⇒ ("abc" "def" "ghi")
{util.stream
}
引数のストリームの全ての対応する要素がそれぞれ、2引数を取るelt=で比較して等しい場合に
#t
を、そうでなければ#f
を返します。
全てのstreamが無限である場合、この手続きは終了しません。
{util.stream
}
streamの最初の方の要素をリストprefixと比較します。各要素は
elt=で比較されます。prefixと全てマッチしたら#t
を、
そうでなければ#f
を返します。最大でもprefixの要素分だけstreamから
要素が取り出されます。
{util.stream
}
(stream-caar s)
= (stream-car (stream-car s))
etc.
[R7RS stream]
{util.stream
}
ストリームのpos番目の要素を返します。posは非負の正確な整数でなければなりません。
{util.stream
}
(stream-first s)
= (stream-ref s 0)
etc.
{util.stream
}
与えられたストリームのうち、最初のcount要素だけを含むストリームを返します。
与えられたストリームがcount要素より少ない要素しか持っていなかった場合、
stream-take
が返すストリームは、元のストリームの終端を越えてアクセスしようとした時に
エラーを投げます。一方、stream-take-safe
が返すストリームは、
元のストリームがcount要素より少なかった場合に、その要素までを返すストリームを
返します。
(stream->list (stream-take (stream-iota -1) 10)) ⇒ (0 1 2 3 4 5 6 7 8 9) (stream-take (stream 1 2) 5) ⇒ stream (stream->list (stream-take (stream 1 2) 5)) ⇒ error (stream->list (stream-take-safe (stream 1 2) 5)) ⇒ (1 2)
註: SRFI-41 (scheme.stream
) もstream-take
を提供していますが、
引数の順序が逆になっています。また、SRFI-41のstream-take
は
元のストリームがcount以下の要素しか持っていなかった場合でもエラーとしません。
{util.stream
}
与えられたストリームのうち、最初のcount要素を取り除いたストリームを返します。
与えられたストリームがcount要素より少ない要素しか持っていなかった場合、
stream-drop
は、アクセスされるとエラーを投げるストリームを返します。
一方、stream-drop-safe
は空のストリームを返します。
註: SRFI-41 (scheme.stream
) もstream-drop
を提供していますが、
引数の順序が逆になっています。また、SRFI-41のstream-drop
は
元のストリームがcount以下の要素しか持っていなかった場合にエラーとせず
空のストリームを返します。
{util.stream
}
elementがstreamの連続する2要素の間に挿入されているような新たなストリームを
返します。
(stream->list (stream-intersperse (stream 1 2 3) 0)) ⇒ (1 0 2 0 3)
{util.stream
}
streamを、predを満たす要素で分割し、
分割されたストリームのストリームを返します。
分割に使われた要素は結果に含まれません。
(stream->list (stream-map stream->list (stream-split (stream 1 3 2 5 7 9 6 8 1) even?)))) ⇒ ((1 3) (5 7 9) () (1))
{util.stream
}
streamの最後の要素を返します。streamが空ならエラーが投げられます。
streamが無限ストリームの場合、この手続きは戻ってきません。
{util.stream
}
streamの最後のcount要素を含むストリームを返します。
countは非負の正確な整数でなければなりません。
もしstreamがcount要素より短ければ、streamがそのまま返されます。
streamが無限ストリームならこの手続きは戻ってきません。
{util.stream
}
streamの最後の要素を除く内容を持つストリームを返します。
streamが空の場合は空のストリームが返されます。
streamは無限ストリームであっても構いません。
{util.stream
}
streamの最後のcount要素を除いた内容を持つストリームを作って返します。
countは非負の正確な整数でなければなりません。
streamの要素数がcountより少なければ、空のストリームが返されます。
streamは無限ストリームであっても構いません。
[R7RS stream]
{util.stream
}
streamの要素数を返します。
streamが無限ストリームの時は戻ってきません。
{util.stream
}
streamの要素数が、それぞれn以上か、nと等しければ#t
を、
そうでなければ#f
を返します。
これらの手続きはstreamの最初のn要素のみを現実化します。
[R7RS stream]
{util.stream
}
streamの要素を逆順にしたストリームを返します。tail-streamが与えられた
場合、逆順にしたストリームの後にそれ付け加えられます。
省略可能なtail-streamはGaucheの拡張です。詳しくは
reverse
の説明を参照してください (他のリスト手続き)。
{util.stream
}
predは、まずstream …それぞれの最初の要素を引数として呼び出され、
次にそれぞれの2番目の要素を引数として呼ばれ、以降いずれかのstreamが尽きるまで
呼ばれます。そして、そのうちpredが真の値を返した数が戻り値となります。
少なくともstreamのうちのひとつは有限でなければなりません。
(stream-count < (stream 1 2 3 4 5) (stream 2 2 2 10 10)) ⇒ 3
{util.stream
}
predをstreamの要素に順に適用し、predが真の値を返したら
直ちにその要因となった要素を返します。streamの残りは現実化されません。
streamの要素の中にpredを満たすものが無かった場合は#f
が返ります。
{util.stream
}
predをstreamの要素に順に適用し、predが真の値を返したら
その要素およびそれ以降の要素からなるストリームを返します。
streamの残りは現実化されません。
streamの要素の中にpredを満たすものが無かった場合は空のストリームが返ります。
[R7RS stream]
{util.stream
}
それぞれ、streamの最初から連続する、predを満たす要素だけからなる
ストリームと、それらの要素を除いたストリームを返します。
(stream->list (stream-take-while even? (stream 2 4 6 1 4 2))) ⇒ (2 4 6) (stream->list (stream-drop-while even? (stream 2 4 6 1 4 2))) ⇒ (1 4 2)
{util.stream
}
ふたつのストリームを返します。最初のストリームは、streamの最初から連続する、
predを満たす/満たさない要素からなるストリームで、
二番目のストリームは残りのストリームです。
(map stream->list (values->list (stream-span even? (stream 2 4 6 1 4 2)))) ⇒ ((2 4 6) (1 4 2)) (map stream->list (values->list (stream-break even? (stream 1 9 6 1 4 2)))) ⇒ ((1 9) (6 1 4 2))
{util.stream
}
predは、まずstream …それぞれの最初の要素を引数として、
次にそれぞれの2番目の要素を引数として、と順次呼ばれます。
stream-any
はpredが真の値を返したらただちに評価を打ち切り、
predが返した値をそのまま返します。
stream-every
はpredが#f
を返したらただちに
評価を打ち切り、#f
を返します。
streamのいずれかが終端に達するまでにpred
が一度も真の値を返さなければ、
stream-any
は#f
を返します。
streamのいずれかが終端に達するまでにpred
が一度も偽の値を返さなければ、
stream-every
は最後のpredの結果を返します。
(stream-any (^[x y] (and (> x y) (list x y))) (stream 1 2 3 4 5) (stream 3 3 3 3 3)) ⇒ (4 3) (stream-every (^[x y] (and (> x y) (list x y))) (stream 6 6 6 6 6) (stream 1 2 3 4 5)) ⇒ (6 5)
{util.stream
}
predは、まずstream …それぞれの最初の要素を引数として、
次にそれぞれの2番目の要素を引数として、と順次呼ばれます。
predが真の値を返したらstream-index
は評価を打ち切り、
そのインデックスを返します。
streamのいずれかが終端に達するまでにpred
が一度も真の値を返さなければ、
#f
が返されます。
(stream-index odd? (stream 2 4 6 7 8)) ⇒ 3
{util.stream
}
member
, memq
, memv
のストリーム版です
(他のリスト手続き参照)。
objと等しい要素をstreamから探し、見つかったその要素を含む
残りのストリームを返します。要素がみつからなければ#f
を返します。
これらの手続きの違いは等価判定述語です。stream-member
は与えられたelt=か、
省略された場合はequal?
を使います。
stream-memq
はeq?
を、stream-memv
はeqv?
を使います。
{util.stream
}
(stream-remove (cut elt= obj <>) stream)
と等価です。
すなわち、入力ストリームからobjと等しい要素を除いた要素を持つ
ストリームを返します。
{util.stream
}
入力ストリームのうち、連続する等しい要素があればその最初以外のものを除いた
ストリームを返します。
要素はelt=で比較されます。省略時はequal?
が使われます。
{util.stream
}
re引数は正規表現オブジェクトか、その文字列表現でなければなりません
(文字列の場合はstring->regexp
で正規表現に変換されます)。
入力ストリームの要素のうち、reにマッチするものだけを含むようなストリームを 返します。
{util.stream
}
streamの各要素をwriterを使ってoportに書き出します。
oportが省略された場合は現在の出力ポートが、
writerが省略された場合はwrite-char
が使われます。
要素の間には何も出力されません。既定値が示すように、 この手続きは文字の遅延ストリームを表示するのに便利です。