第29回
■
■SqueakではじめるSmalltalk入門 第29回
■
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。前回に引き続き、ブロックの効用と絡めながら一般的な制御構造がどのようにメッセージ送信式で表現されるのかを見てゆきましょう。
▼永久ループ
ブロックに対してrepeatを送信すると永久ループになります。停止するには、cmd+.(ピリオド)でユーザー割り込みをかける必要があります。
| pen |
pen _ Pen new.
pen defaultNib: 1.
pen color: Color red.
pen place: Display center.
[pen turn: 360 atRandom; go: 2] repeat
▼回数を指定した繰り返し
有限回数の単純繰り返しは、繰り返したい数を表わす自然数に対して、timesRepeat: [...]というメッセージを送信します。繰り返したい手続きは、ブロックでパラメータ(引数)として与えます。
| pen |
pen _ Pen new.
pen defaultNib: 1; color: Color blue; place: Display center.
10000 timesRepeat: [pen turn: 360 atRandom; go: 2].
Display restore
▼インデックス付き繰り返し
いわゆるfor-nextループのようなものを意識したメッセージ式としては、#to:do:というメソッドが使用できます。レシーバは始点、第一パラメータは終点の整数で、第二パラメータとして繰り返す処理のブロックを与えます。繰り返し処理のブロックは、ひとつのブロック変数が必要で、これを介して繰り返し時のインデックスが参照可能です。
World findATranscript: nil.
1 to: 10 do: [:idx | Transcript cr; show: idx printString]
降順にするときは、#to:by:do:を使います。
World findATranscript: nil.
10 to: 1 by: -1 do: [:idx | Transcript cr; show: idx printString]
ただ、#to:do:や#to:by:do:は、本当にfor-nextの焼き直し的な意味しかないメソッドなので、メッセージ送信の体裁は整えられていても、けっしてSmalltalkらしい表現とは言えません。通常はCollection >> #do:を使います。
World findATranscript: nil.
(1 to: 10) do: [:each | Transcript cr; show: each printString]
字面では括弧で括っただけなのですが、メッセージ式としては意味がずいぶんと違ってきます。#to:do:の場合との違い(レシーバやメッセージの意味)を改めてじっくり考えてみるのもおもしろいと思います。(1 to: 10)というのは、インターバル(an Interval)と呼ばれる範囲の定まった等差数列オブジェクトを生成する式です。この#do:に象徴される文字列や配列の仲間をレシーバとした、きわめてSmalltalkらしい繰り返し処理の方法については、この後、引き続きご紹介する予定です。
▼条件付き繰り返し
条件に対して、whileTrue: [...]あるいは、whileFalse: [...]というメッセージを送信することで、実現しています。パラメータに繰り返したい処理をブロックで与えるほかに、終了もしくは継続条件であるレシーバもブロックである点に留意する必要があります。
次のスクリプトでは、キーボードのシフトキーの押し下げを感知して繰り返しを終了します。
| pen |
pen _ Pen new.
pen defaultNib: 1; color: Color yellow; place: Display center.
[Sensor shiftPressed]
whileFalse: [pen turn: 360 atRandom; go: 2].
Display restore
条件をnotを送信することで反転させれば、whileTrue:で同じことが可能です。
| pen |
pen _ Pen new.
pen defaultNib: 1; color: Color yellow; place: Display center.
[Sensor shiftPressed not]
whileTrue: [pen turn: 360 atRandom; go: 2].
Display restore
Sensorは、an EventSensorを束縛するグローバル変数で、入力デバイスの状態を手軽に知りたいときに用います。ただ、Squeakの前身であるSmalltalk-80システム時代から使われているレガシーなサービスなので、簡単なスクリプトで便利に使う程度にとどめておくのがよいようです。キーボードの状態の他にも、マウスボタンの押し下げ状態などを知りたいときにも使えます。
EventSensorのスーパークラスに当たるInputSensorのmodifier key、mouse、cursorなどのプロトコル(メソッドカテゴリ)をブラウズすると、マウスやキーボードのどういった状態を取り出すことができるのかを知ることができます。
▼and/or
制御構造ではありませんが、条件を記述する際に用いる論理積、論理和の表現でもブロックは活用されます。お馴染みの論理演算二項式をシミュレートした二項メッセージ式としては、
true | false " => true (OR) "
true & false " => false (AND) "
というのがありますが、これとは別にキーワードセレクタとして#or:、#and:が用意されています。
true or: [false] " => true "
ture and: [false] " => false "
もちろん評価結果は同じになりますが、キーワードセレクタを使ったメッセージでは、二項セレクタの#|や#&の場合と違って、パラメータがブロックでなければなりません。これは、レシーバの内容によって、パラメータの処理が省略できる場合に対処するためのものです。たとえば、#or:の場合、レシーバがfalseならパラメータの評価の結果で結論は左右されますが、レシーバがtrueならばパラメータの評価は不要…というような状況を想定しています。
先のスクリプトで、繰り返しの終了条件として「シフトキーの押し下げと同時に画面のクリックする」というものを表現したい場合には、レシーバである条件のブロック内に次のように記述します。
| pen |
pen _ Pen new.
pen defaultNib: 1; color: Color yellow; place: Display center.
[Sensor shiftPressed and: [Sensor redButtonPressed]] " ← ココ "
whileFalse: [pen turn: 360 atRandom; go: 2].
Display restore
このページを編集 (4938 bytes)
|
以下の 1 ページから参照されています。 |
This page has been visited 897 times.