必要に応じて前後の要素にもアクセスできる each 2


id:sumim:20070614:p1 の続き。


spiral さんに #peek を使ってはどうかというコメントをいただいて、なるほどその手があったか…と気がついたので。


Smalltalk には「位置指定可能ストリーム(a PositionableStream)」というものがあって、順序付きコレクションをこれに変換(ラップ)して使用できます。この位置指定可能ストリームでは、全要素をなめる祭に、通常は終わりがくるまで next というメッセージで要素を取り出すことを繰り返す…というイディオム

| stream |
stream := (1 to: 9) readStream.
[stream atEnd] whileFalse: [Transcript cr; show: stream next]


を用いるのが常ですが、元の順序付きコレクション同様、do: [:each | ... ] というメッセージ(Ruby の #each にあたる)にも応答できるようになっています。さらに、Squeak Smalltalk では位置指定可能ストリームであれば隣接する要素の“のぞき見(peek)”も可能なので、こんなふうに書くことができるというわけです。

| stream |

World findATranscript: nil.
Transcript cr.

stream := (1 to: 9) readStream.
stream do: [:each | Transcript cr; show: {stream peekBack. each. stream peek}].
=> #(nil 1 2)
   #(1 2 3)
   #(2 3 4)
   #(3 4 5)
   #(4 5 6)
   #(5 6 7)
   #(6 7 8)
   #(7 8 9)
   #(8 9 nil)


なお、Cincom Smalltlak(VisualWorks)では、PositionableStream が PeekableStream のサブクラスとして定義され、のぞき見可能であることが明示的にされています。