復習のページ2
こちらからの続き…
>だからその場(普通ワークスペース?)に評価をprint-itさせるために必須な最終行の「^」はいらない。
反応の結果になにを期待するか…と申し上げたのはそういう意味です。本来なら、たち も たちの数は? 同様に ^ を書くべきなのですが、当初は print-it での評価を想定しておらず、インスペクタの表示という派手な反応が返るので間違って print-it したとしてもプリント結果は無視していただけるだろう(平たく言えば、気が付くことはあるまい…(^_^;))との、また、そもそも printOn: をいじっていなかったので、print-it させただけで #(a ムーンレイス a ムーンレイス a ムーンレイス) などとプリントされても何のことだか分からない、という状況に陥ることが容易に予想され、print-it よりむしろインスペクタで見せた方がよいだろうという判断に基づき、インスペクタ表示とは直接関係のない ^ は書くべきではないという結論に至った自らの思考過程を思い出しました。振り返れば皮肉にも、^ をあえて書かなかったこと、Array で結果を見せたこと、インスペクタを使ったことで、ご理解を促すよう配慮したつもりが、すべてが後々の混乱に拍車をかけることにつながってしまっていたわけですね。ごめんなさい。--sumim - 2002-07-20, 12:44:48
ですから、ムーンレイスのインスタンスたちを手軽に一覧する目的を終えた「たち」のメソッド(仕様書)は今現在、もはや、
たち
"生存している人間たちを返す"
^ self allInstances
とするのが正しく、そもそも当初の“「ムーンレイス たち」の do-it でインスペクタを開く”という仕様自体が不適切なものだったと考えるのがよいと思います。くだんの説明を終えた時点で、そうしたことに言及すべきでした。ちなみに、インスペクタを開きたければ(そうした反応を期待するなら)、上の修正を施したあと「ムーンレイス たち」というメッセージ式を inspect-it するか、でなければ「ムーンレイス たち inspect」を do-it するほうが美しいですしずっと自然です。--sumim - 2002-07-20, 12:50:35
KYさんからも掲示板で助言をいただきつつ漸進しております。しばし停滞にお付き合い下さいm(_ _)m。
inspectの件はやっと明るくなりました。
>たち
>"生存している人間たちを返す"
>^ self allInstances
直して試してみました。大丈夫、これは理解できました。
>たとえば、先に出てきた、
>1. 2. 3. 4. 5
>の print-it の結果は 5 だけでしたよね。
この複数行一括print-itも大きな鍵のようです。<わたしにとって
先の「ミラン='処理終わり'」の件ですが、これはミランというグローバル変数に「ムーンレイス、瞳は灰、男、初期値で好意対象は'ディアナ・ソレル'」というメッセージを送り(次々に新しいオブジェクトが生まれ)、最後にミランにムーンレイスとは全く性格の異なるオブジェクト=文字列'処理終わり'を送ってしまった。だからムーンレイスはおろか人間ですらなくなった……と理解してよろしいでしょうか?
最終行を削除すると、print-itの評価はムーンレイス(class)となります。
メッセージ式の最後の「^」は、登場人物が上の2行で様々なメッセージを受け取った「登場人物」を最後にミランに送るための「^」で、これによって「ミラン」はやっと完成する。
……もの凄く基本的なところが理解できていなかったのですね(T-T)?
>刺激の反応としてどんなオブジェクトを返すかを決めるための最終処理
という意味がやっとわかったような気がします。
まだ不十分かも知れませんがm(_ _)m --さ茂 - 2002-07-20, 23:04:41
先の「ミラン='処理終わり'」の件ですが、これはミランというグローバル変数に「ムーンレイス、瞳は灰、男、初期値で好意対象は'ディアナ・ソレル'」という値を順々に送り(次々新しいオブジェクトが生まれ)、最後にそれに'処理終わり'という文字列を送ってしまった。それだけのことと理解してよろしいでしょうか?
たとえば「ミラン _ ムーンレイス の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」を do-it したときに何が起こるかを順を追って箇条書きにしてみましょう。
- まず「ミラン _ 」はこの時点ではいったん無視され、「ムーンレイス の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」を実行。
- 「ムーンレイス」「の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」に分解し「の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」がメッセージ、「ムーンレイス」がそのメッセージを受け取るオブジェクトと見なす。
- 「ムーンレイス」に「の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」というメッセージを送る。
- 「ムーンレイス」はその設計図・仕様書である「ムーンレイス class」に「の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」というメッセージへの対応の仕方に関する記述(メソッド)があるか調べるが見つからない。
- そこで「ムーンレイス class」のスーパークラスである「人間 class」に同記述があるか調べ、そこで「人間 class >> #の:瞳の色は:で:」を見つける。
の: ある名前 瞳の色は: ある色 で: 男か女
"基本的な状態を設定した「ある人間」を返す"
| 登場人物 |
登場人物 _ (self new の: ある名前 瞳の色は: ある色 で: 男か女).
self = ムーンレイス
ifTrue: [登場人物 が好きなのは: (self の: 'ディアナ・ソレル')]
ifFalse: [登場人物 が好きなのは: (self の: 'キエル・ハイム')].
^ 登場人物
- 1行目で宣言された「ある名前」「ある色」「男か女」という偽変数に、それぞれ、'ミラン・レックス'、'灰色'、'男' というオブジェクトをつなげる。
- 3行目で宣言された「登場人物」というテンポラリ変数を作る(無条件で nil というオブジェクトがつながっている)。
- 4行目の「登場人物 _ (self new の: ある名前 瞳の色は: ある色 で: 男か女)」を実行するが、最初と同様に「登場人物 _ 」はいったん無視。「self new の: ある名前 瞳の色は: ある色 で: 男か女」を実行する。
- 偽変数の self には「ムーンレイス」がつながっている。偽変数につながっているオブジェクトで上のメッセージ式を書き直すと「ムーンレイス new の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」となる。
- 「ムーンレイス」「new」「の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」に分解する。これは「オブジェクト メッセージA メッセージB」型。オブジェクトが「ムーンレイス」でメッセージAが「new」、メッセージBが「の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」となるので、まず、メッセージBを無視し「オブジェクト メッセージA」つまり「ムーンレイス new」を実行する。
- 「new」というメッセージを受けた「ムーンレイス」は自分が持っている設計図に従って“あるムーンレイス”つまり自らのインスタンスを作る。
人間 subclass: #'ムーンレイス'
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'ターンA-ガンダム'
- だが、具体的な設計(どんなインスタンス変数を持つか)はそのスーパークラスである「人間」に記述されているのでこちらに従う(実際にはこれはクラスを作るためのメッセージ式に過ぎませんがここでは便宜的に設計図、つまり、どんなインスタンス変数を持つかを記述したものとして解釈しています)。そこには「名前」「瞳の色」「好意対象」「憎悪対象」「性別」というインスタンス変数を持つことが記述されている。それらには nil がつながっているインスタンス“あるムーンレイス”が作られる。同時にこの“あるムーンレイス”が「ムーンレイス new」というメッセージ式の結果として返される。
Object subclass: #'人間'
instanceVariableNames: '名前 瞳の色 好意対象 憎悪対象 性別 '
classVariableNames: ''
poolDictionaries: ''
category: 'ターンA-ガンダム'
“あるムーンレイス”(名札=なし)の内部状態
名前 …… nil
瞳の色 …… nil
好意対象 …… nil
憎悪対象 …… nil
性別 …… nil
- 「オブジェクト メッセージA メッセージB」の「オブジェクト メッセージA」の実行が終わったので、メッセージBの部分が実行される。具体的には「オブジェクト メッセージA」、つまり「ムーンレイス new」返ってきたオブジェクト“あるムーンレイス”にメッセージBである「の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」を送信する。
- メッセージを受けた“あるムーンレイス”は、自らの設計図・仕様書である「ムーンレイス」でメッセージ「の:瞳の色は:で:」への反応のしかたを探しスーパークラスの「人間」で見つける。
の: ある名前 瞳の色は: ある色 で: 男か女
"主に初期状態のある人間に対し基本的な状態を設定する"
名前 _ ある名前.
瞳の色 _ ある色.
性別 _ 男か女
- 1行目で宣言された「ある名前」「ある色」「男か女」という偽変数に、それぞれ、'ミラン・レックス'、'灰色'、'男' というオブジェクトをつなげる。
- 3行目以降で、「名前」「瞳の色」「性別」というそれぞれ今まで nil がつながっていたインスタンス変数に、「ある名前」「ある色」「男か女」という偽変数につながっているオブジェクトを(nil へのつながりを放棄して)つなげる。
“あるムーンレイス”(名札=なし)の内部状態
名前 …… 'ミラン・レックス'
瞳の色 …… '灰色'
好意対象 …… nil
憎悪対象 …… nil
性別 …… '男'
- このメソッドには ^ がないので、^ self、つまり ^“あるムーンレイス”を実行し、自分自身を反応の結果として返す。
- 「人間 class >> #の:瞳の色は:で:」に戻り、いったん無視した「登場人物 _ 」に着目する。前の項で書いたように右辺の「self new の: ある名前 瞳の色は: ある色 で: 男か女」の結果として“あるムーンレイス”が返ってきているので式としては 登場人物 _ “あるムーンレイス”となる。したがって「登場人物」というテンポラリ変数に“あるムーンレイス”がつながる。これで今まで参照方法がなかった“あるムーンレイス”を「登場人物」と表記し参照することができるようになる。
“あるムーンレイス”(名札=登場人物)の内部状態
名前 …… 'ミラン・レックス'
瞳の色 …… '灰色'
好意対象 …… nil
憎悪対象 …… nil
性別 …… '男'
- 「self == ムーンレイス ifTrue: [登場人物 が好きなのは: (self の: 'ディアナ・ソレル')] ifFalse: [登場人物 が好きなのは: (self の: 'キエル・ハイム')]」を実行する。これも「オブジェクト メッセージA メッセージB」型。オブジェクトが self につながっている「ムーンレイス」、メッセージAが「== ムーンレイス」、メッセージBが「ifTrue: ブロックA ifFalse: ブロックB」である。まず「オブジェクト メッセージA」、つまり「ムーンレイス == ムーンレイス」を実行。メッセージ「== オブジェクト」は受け手のオブジェクトが == 以降のオブジェクトと同一なら true を、そうでなければ false を吐きださせる。従って「ムーンレイス == ムーンレイス」とういうメッセージ式は true を返す。
- 返ってきたオブジェクトにメッセージBが送信される。具体的には true に「ifTrue: ブロックA ifFalse: ブロックB」というメッセージを送信。true はこれを受け取るとブロックBを無視して、ブロックAに value というメッセージを送りその結果を反応の結果として返す。これはブロックB内のコード、つまり「登場人物 が好きなのは: (self の: 'ディアナ・ソレル')」を実行することを意味する。
ifTrue: ブロックA ifFalse: ブロックB
^ブロックA value
- 登場人物には“あるムーンレイス”がつながっている。self には「ムーンレイス」がつながっているので“あるムーンレイス”に「が好きなのは: (ムーンレイス の: 'ディアナ・ソレル')」というメッセージを送ることになる。まず、「が好きなのは:」に伴わせるオブジェクトを「ムーンレイス の: 'ディアナ・ソレル'」を実行して決める。
- 「ムーンレイス」は「の: 'ディアナ・ソレル'」、つまり 'ディアナ・ソレル' という文字列を伴った「の:」というメッセージを受け、その設計図・仕様書である「ムーンレイス class」でその仕様書を探す。
の: ある名前
"ある名前のある人間を返す"
| 候補 |
候補 _ self allInstances select: [ :ある人間 | ある人間 の名前 = ある名前 ].
^ (候補 size > 0) ifTrue: [ 候補 first ] ifFalse: [ nil ]
- 「ある名前」という偽変数には「の:」に伴って送られた'ディアナ・ソレル'という文字列がつながる。まだ説明していない Array がらみなので詳しくは書きませんが、なんやかやあって、我々がディアナ・ソレルと認識しているムーンレイスのインスタンス(便宜的に「ムーンレイス の: 'ディアナ・ソレル'」と呼称)が、この反応の結果として返される。
- 改めて、“あるムーンレイス”に「が好きなのは: (ムーンレイス の: 'ディアナ・ソレル')」が送信される。“あるムーンレイス”は自らの設計図・仕様書である「ムーンレイス class」を探して「が好きなのは:」のメソッドをスーパークラスである「人間 class」に見つける。
が好きなのは: ある人間
好意対象 _ ある人間
- 1行目で宣言されている偽変数「ある人間」に「ムーンレイス の: 'ディアナ・ソレル'」がつながる。2行目で「好意対象」というインスタンス変数にそれまでつながっていた nil とのつながりをキャンセルして、代わりに「ある人間」につながっているオブジェクトがつながる。
“あるムーンレイス”(名札=登場人物)の内部状態
名前 …… 'ミラン・レックス'
瞳の色 …… '灰色'
好意対象 …… ムーンレイス の: 'ディアナ・ソレル'
憎悪対象 …… nil
性別 …… '男'
- このメソッドには ^ がないので反応の結果としては自分自身、つまり“あるムーンレイス”が返る。ブロックAの内容はこれで終わりなので、ブロックAの実行結果もこれ、つまり“あるムーンレイス”が返る。しかし帰った場所は代入文の右辺でもないし、新しく送られるのを待っているメッセージCもないので、この反応結果自体は無視される。
- 最後(で問題)の「^ 登場人物」が実行される。「ムーンレイス の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」の結果として「登場人物」につながっている“あるムーンレイス”が反応の結果として返される。ちなみにこの文がないと「^ self」つまり「^ ムーンレイス」が補われ、反応の結果は「ムーンレイス」となる。「^ 'ある文字列'」とした場合は、反応の結果は「'ある文字列'」となる。なお、このメソッドの実行が終了した時点で「登場人物」というテンポラリ変数はその機能、つまり、“あるムーンレイス”とのつながりを失う。
- 最初、いったん無視した「ミラン _ “右辺”」が実行される。右辺の実行(反応の)結果は上に書いたとおり。“あるムーンレイス”が返れば“あるムーンレイス”を、「ムーンレイス」「'ある文字列'」が返ればそれぞれを「ミラン」につなげる。後二者の場合、“あるムーンレイス”は生存持続条件である「どこかにつながっていなければならない」を失い、Squeak にゴミとして抹殺される。
“あるムーンレイス”(名札=ミラン)の内部状態
名前 …… 'ミラン・レックス'
瞳の色 …… '灰色'
好意対象 …… ムーンレイス の: 'ディアナ・ソレル'
憎悪対象 …… nil
性別 …… '男'
こんな物語が「ミラン _ ムーンレイス の: 'ミラン・レックス' 瞳の色は: '灰色' で: '男'」の do-it で展開されています。--sumim - 2002-07-21, 01:04:03
おはようございます。
分解するとさらに混乱しますが、基本的にオブジェクトへのメッセージの送り方、反応の仕方の順が理解不十分でした。
この箇条書きを抜き出してじっくりと読み返して自分なりに消化できるかやってみます。しばしお待ちをm(_ _)m。
毎度のことですが、基本的な「メッセージの送り方・反応の返り方」の不理解が全てこの停滞の原因ですね……。まったくもって不出来な生徒ですみませんm(_ _)m。--さ茂 - 2002-07-21, 08:24:07
そうですね。ただ、そこさえきちんとイメージできるようになれば、まだ説明をしていない Array の挙動のところを除いて、前述の箇条書き、ひとつひとつに合点がいくようになると思います。経験から、これがすっぽりとはまったときはとても気持ちがよいものですので是非、がんばってください。逆に、分解して混乱が増すときは、やはりなにかの基本的理解が足りていないでしょう。この機会に、しっかりとかたづけておきたいですね。オブジェクトにメッセージを送り、その反応として返ってきたオブジェクトにまたメッセージを送るという連鎖的作業と、すぐにメッセージを送ることができないオブジェクトは反応として返ってきたときいったん変数につなぎとめておく。たったこれだけのことで、目の前で起きているかなりの部分を説明可能なシステムは希有で面白いと私は考えています。--sumim - 2002-07-21, 13:31:27
このページを編集 (14148 bytes)
|
以下の 1 ページから参照されています。 |
- 復習のページ 最終更新: 2002-07-20, 13:47:16 <192>
This page has been visited 2860 times.