第27回
■
■SqueakではじめるSmalltalk入門 第27回
■
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。定番オブジェクト解説の三回目は「ブロック」です。
ブロック(a BlockContext)は手続きをオブジェクトとして取り扱えるようにしたものです。制御構造構文を持たないSmalltalk言語では、苦肉の策…というわけではないのですが、ブロックをパラメータに添えたメッセージ送信を行なうことで、制御構造を実現します。
1 < 2 ifTrue: [3 + 4] ifFalse: [5 - 6] "=> 7 "
特別な制御構造を持たず、ブロックとメソッド(関数)の組み合わせで同様の機能を提供するということは、Smalltalk言語においては、ユーザーがその必要に応じて、自由に制御構造を創造し言語機能を拡張できることを意味します。
ブロックは、通常の処理を大括弧「[ ]」で括ることで表現できます。
3 + 4 "=> 7 "
[3 + 4] "=> a BlockContext "
通常のオブジェクトと同様に、メッセージのレシーバになったり、変数に束縛(代入)したり、パラメータ(引数)として渡したりできます。制御構造的なしくみでは、最後の性質を利用しているわけです。
| block |
block _ [3 + 4].
World findATranscript: nil. "トランスクリプト呼び出し"
Transcript
cr; show: 7 = block; "=> false "
cr; show: block = block; "=> true "
cr; show: block class "=> BlockContext "
処理を実行するためには改めてメッセージ「value」を送る必要があります。
[3 + 4] value "=> 7 "
関数のように引数(パラメータ)を持たせることも可能です。パラメータを束縛する変数を「ブロック変数」と呼び、ブロック表現の先頭に列挙して宣言します。たとえば、パラメータを二乗して返すブロックは、次のように表現します。
[:x | x * x]
ブロック変数を宣言するとき、その頭にはコロン「:」を付けます【註1】。ブロック変数の宣言が終わったら「|」を置いて、ブロック本体の処理と区別します。ブロック変数が複数あるときは、スペースで区切って列挙します。
[:x :y | x + y]
処理を実行するときは「value」ではなく「value: arg」や「value: arg1value: arg2」を使います。なお、ブロックの持つブロック変数の数と、評価時に与えるパラメータの数は一致していなければいけません。
[:x | x * x] value: 3 "=> 9 "
[:x :y | x + y] value: 3 value: 4 "=> 7 "
[:x :y | x + y] value: 3
"=> Error: This block requires 2 arguments. "
#value:value:value:value:、つまりパラメータが四つのブロック向けのものまで用意されていますが、追いつかないときは、#valueWithArguments:でパラメータを配列に収めた状態で渡すこともできます。
[:x :y | x + y] valueWithArguments: #(3 4) "=> 7 "
余談ですが、パラメータの数を動的(実行時)に知りたいときは、メッセージ「numArgs」を送ればブロック自身が答えてくれます。
[3 + 4] numArgs "=> 0 "
[:x | x * x] numArgs "=> 1 "
[:x :y | x + y] numArgs "=> 2 "
ブロックは無名の関数、あるいは、どのクラスにも属さない無名のメソッドのように考えると理解しやすいことがあります。LISPに通じておられるかたは「ラムダ式に相当する」と言えば、ピンと来るはずです。【註2】
[:x :y | x + y]
(lambda (x y) (+ x y))
註1:このコロンは、メソッド定義におけるメッセージパターン(一行目)において、キーワードがない状態を想定してその書式を模したものだと言われています。実際、こうした書き方はあまり推奨されていませんが、メソッド定義のメッセージパターンと同じように書くこと、つまり、ブロック変数とコロンの間にスペースを入れることも許されています。
[:x :y | x + y] " OK "
[: x : y | x + y] " OK "
[: x: y | x + y] " NG "
註2:ただし、Squeakは古典的なSmalltalkシステムであるため、ブロックがきちんとしたクロージャになっていません(ブロック内に独自のテンポラリ変数が持てず、テンポラリ変数を定義しても外部から自由にアクセスできてしまう。つまり“クローズ”してしない)。したがって、再帰や(疑似)並列処理には使えなかったり、使えても、いろいろと注意する必要があります。なお、最新のSmalltalkであるVisualWorksやANSI準拠のSmalltalk言語処理系では、この点は改良されていて、ブロックはクロージャとして問題なく使用できます。
このページを編集 (3951 bytes)
|
以下の 1 ページから参照されています。 |
This page has been visited 1171 times.