« おばけつぶやき帳 | トップページ | テスト »

2008年7月14日 (月曜日)

問2:第6回

iPhone騒動で、この講座のアップをすっかり忘れていました。悪しからず!!

という事で、第6回ですが……なんと暑い日々が続いているのでしょうかネ
相変わらず多治見の夏は暑いと騒がれていますが、今年はその多治見より暑い新顔が静岡に出現したと、つい二三日前に報道されていましたね。どうせ暑いのなら今年は単独日本一と願っている私ですが:

そう書いた途端に、オバケ姉さんから暑中見舞いのコメントが……:
わが家の暑さ対策は、暑さに抗わないことを基本にしています。エアコンも扇風機もないわが家の暮らしでは暑さと親しむ以外に方法がないのである。狭い家なので、日中は窓を開けておけば多少は風が通るし、夜はこれも窓を開けて寝ればそれなりに涼しく寝られる。
幸いな事に、山の中ではないが山も川も近いため、都会のコンクリート・ジャングルの熱帯夜に比べれば遥かにしのぎやすい。要は「慣れなのだ」と思う。
人間「易きに流れれば、自然から見放される」と言う事だろうか?

閑話休題

さて本題に戻り;

無限循環……手順5では簡単に「無限循環に陥ってしまう」と書いてしまったのですが、意味する処は理解いただけたでしょうか?
またそれを解決するために最終的にどのようにスクリプトを変更したのかも理解できたでしょうか?

無限循環と言うのは例えば、売価フィールドに値を入力すると;

if the target contains “BaiKa” then
answer “Which is the Next ?” with “GenKa” or “NeIre” or “Cancel”
end if

と、次の入力フィールドを尋ねるのですが、その選択肢が「原価フィールド」であっても「値入フィールド」であっても、そのフィールドでまた同じ質問を受けることになります。つまり、売価、原価、値入の各フィールドを言ったり来たりするだけで肝心の答えを得ることはできないわけです。この原因は「問いのたて方が悪」かったからです。ではどんな「問い」をたてれば良いのでしょうか。
ここでの良い問いのたて方は恐らく次の様になると思います。つまり、最終的に得たいモノは何かをはっきりさせるような問いということです。その為に、変更したスクリプトが次の部分になります。

if the target contains “BaiKa” then
put empty into fld “GenKa”
put empty into fld “NeIre”
answer “what do you enter next ?” with “GenKa” or “NeIre” or “Cancel” as sheet

つまり、answerで尋ねている内容が異なるわけです。変更したスクリプトでは、次に値を入力するフィールドを指定しているということです。これで一応「無限循環」は避けられるのですが、全体のスクリプトはIF条件文を沢山含んだ複雑なものになってしまいます。
ところでこうして書き直してきたスクリプト全体を今一度鳥瞰してみると、今やろうとしている「『問2に応える』スクリプトを書く」という目的にとって、本当にこの方法がベストなのかという疑問が沸いてきませんか? つまり、こうしたIF条件文を多く含む解法がまどろっこしくなってきませんか?いっそのこと初めから「求めたいのは何か」を明確にしてしまった方が、このスクリプト全体、つまりはこうしたアプリケーション全体が簡潔なものになるように思えませんか?

こうした議論(講義)のすすめ方は幾分意地悪なのかも知れませんが、お許し下さい。つまり私自身は既にどうすれば良いのかを判っていて、わざと議論を誤った方向に導いて、ホ~ら間違ったでしょ、と言っている……。そんな感じがすると思います。こうした問題のすすめ方を論理学では「論点選手の虚偽」というらしいのですが(確認はしていません)。でも、これはアプリケーションを作成する上でどんなところに気をつけなければならないかを例示しながら説明している事の現れとして、今のところは、理解しておいて下さい。

という処で、手順6では一旦今まで考えてきた流れを全て忘れてしまい、新たな方法でスクリプトを書き直すという事にします。それは「フィールドに値を入れる」ことでハンドラを起動させるという事ではなく、一つのボタンをクリックする事で値を入れるべきフィールド、フィールドに入れるべき値、それらを使った計算を実行してしまうスクリプトを書くと言う事です。


Itoh033

まず、上の図のように新しくボタンを一つ作り、名前を「KeiSan」、ラベルを「計算」とします。それ以外の部分は変更しません。ボタンができあがったら次のスクリプトをカードスクリプトとしてカードに書き込みます。つまり、ボタン・オブジェクトにスクリプトを書くのではなく、今回書いてきているスクリプトと同じくカード・オブジェクトに書いて行くという事です。書いて行く位置はどこでも良いのですが、後々の事も考えて今回は【スクリプト2の9】の「on enterInField」との前に新たな行を作って、以下のスクリプトを書いて行く事にします。

【スクリプト2の10】
on mouseUp
if word 1 of the target is “button” and word 2 of the target is quote & “KeiSan” & quote then
put empty into fld “BaiKa”
put empty into fld “GenKa”
put empty into fld “NeIre”

set the locktext of fld “BaiKa” to true
set the locktext of fld “GenKa” to true
set the locktext of fld “NeIre” to true

set the showfocusborder of fld “BaiKa” to false
set the showfocusborder of fld “GenKa” to false
set the showfocusborder of fld “NeIre” to false
else
put “bad expression”
end if
end mouseUp

このスクリプトは、mouseUpハンドラーになります。従って、カード上でmouseUpメッセージが発せられると反応します。実際には、計算ボタンが押された時のみ対応するスクリプトを実行させたいので、今までと同じように、the targetでオブジェクトを特定して計算ボタンかどうかを判断しています。今回のthe targetの使い方では、the targetで得られるthe targetの内容をwordで区切ったもので二重にチェックを掛けています。

the targetを使った時に得られるのはオブジェクトの種類とオブジェクトの名前の二つの要素です。その形は通常「button “KeiSan”」(オブジェクトのタイプ、半角スペース、引用符で括られたオブジェクトの名前)の様になります。wordというのはRunRevで良く使われるチャンク表現の一つで、英語の単語に当たります。英語、でもドイツ語でもフランス語でも、つまり欧米語ではword(単語)とword(単語)の区切りにはスペースが用いられます。一般的に漢字圏の言語では単語は「意味を持つ一つの塊」として捉えられるため単語と単語の区別にスペースなどを用いません。従って英語に似た表現型式を持つRunRevのスクリプトではスペース(半角スペース)の前と後ろで単語の区別を行います。つまりthe targetで得られる「button “KeiSan”」は二つのwordからなる文字列という事になり、word 1 of the targetで「button」がword 2 of the targetで「“KeiSan”」が得られるわけです。さらにword 2の場合、“の後にも”の前にも空白がないため「“KeiSan”」全体がwordとして認識されます。

word 1 of the target isという様な表現の仕方をチェンク表現式といいますが、チャンク表現式の場合「is」の後にくる参照すべきwordは必ず「“”」で括るというのがルールのため、「“KeiSan”」の様にwordに「“”」が含まれる場合には「quote & “KeiSan” & quote」と引用符を表す定数(constant)を使う事になります。その場合、引用符としてのquoteとwordとしての“KeiSan”が途中にスペースを含まない一つの文字列として扱えるよう必ず「&」を用いて連結しなければなりません。
こうして出来上がったのが;if word 1 of the target is “button” and word 2 of the target is quote & “KeiSan” & quote thenというIF条件文になります。お判りの事と思いますが、この条件文では「word 1 of the target is “button”」と「word 2 of the target is quote & “KeiSan” & quote」の両方の条件が成り立つ場合のみ全体の条件が真となりますので、計算ボタンの発したmouseUpメッセージのみに反応するわけです。

さてここまでの説明が理解できたところで、実際に今書き込んだスクリプトをテストしてみて下さい。計算ボタンでマウスをクリックしたり、カードやフィールドの上でマウスをクリックしてみて下さい。どんな事が起こりますか?

計算ボタンでマウスをクリックした場合、実際には最初の一回だけ変化が起きますが、二回目以降は変化が起きません。(或いは、全く変化が起きないかも知れません。それは今までのテストの環境や現在のスタックの情況により異なってくるという事です。)カードやフィールドの上でマウスをクリックすると、その度に「put “bad expression”」がメッセージボックスに現れるはずです。

【スクリプト2の10】にある;put empty into fld “BaiKa”からset the showfocusborder of fld “NeIre” to falseまでは、これから書き込んでいく実際のスクリプトのための準備を行っている部分で、フィールドに入力ができないようにする処理をしています。詳しい事はここでは扱いませんので割愛しますが、後々どこかで説明する機会があろうかと思います。


さていよいよスクリプトを変更していきましょう。手始めに、【スクリプト2の10】の「put “bad expression”」を「answer “You MUST push CORRECT button !!” as sheet」と書き換えます。これにより、計算ボタン以外の場所でマウスがクリックされた時に注意を喚起します。次に、最終的に「原価」「売価」「値入」のうちの何を得たいのかを質問するための処理を書いて行きます。書き終えたら、さらに「原価」「売価」「値入」のどれかを得るための処理を新たなハンドラーとして書き込んで行きます。こうして得られたのが【スクリプト2の11】になります。

【スクリプト2の11】
on mouseUp
if word 1 of the target is “button” and word 2 of the target is quote & “KeiSan” & quote then
put empty into fld “BaiKa”
put empty into fld “GenKa”
put empty into fld “NeIre”

set the locktext of fld “BaiKa” to true
set the locktext of fld “GenKa” to true
set the locktext of fld “NeIre” to true

set the showfocusborder of fld “BaiKa” to false
set the showfocusborder of fld “GenKa” to false
set the showfocusborder of fld “NeIre” to false

answer “WHAT do you WANT to GET ?” with “GenKa” or “NeIre” or “BaiKa” or “Cancel” as sheet
if it is “Cancel” then
exit to top
end if
if it is “GenKa” then
getGenKa
end if
if it is “NeIre” then
getNeIre
end if
if it is “BaiKa” then
GetBaiKa
end if
else
answer “You MUST push CORRECT button !!” as sheet
end if
end mouseUp

on getGenKa
put “getGenKa”
end getGenKa

on getNeIre
put “getNeIre”
end getNeIre

on GetBaiKa
put “getBaiKa”
end GetBaiKa


蛇足ですが、注意をして欲しいのは、今まで一切【スクリプト2の9】として書いたものを削除したり、訂正したり、或いはコメント化したりをしていないという事です。それは何故かは今のところ内緒にしておきます。

ではここで恒例のテストです。【スクリプト2の11】をコンパイルした後、ブラウズ・モードで計算ボタンをクリックしたり、カード上をクリックしたりして動きを確認して下さい。最終的にはメッセージボックスに「getGenKa」「getNeIre」「getBaiKa」という文字列が表示されれば、スクリプトは正常に動いているという事です。


ではいよいよ本質的な部分のスクリプトを書いて行きます。「getGenKa」「getNeIre」「getBaiKa」がそれで、これらをそれぞれハンドラとしていきます。つまり「getGenKa」では原価を算出し、「getNeIre」では値入を算出し、「getBaiKa」では売価を算出するためのスクリプトを書いて行きます。念のためもう少し詳しく説明すると、getGenKaハンドラーでは「原価を得る」ために必要な売価と値入率の入力を促し、getNeIreハンドラーでは「値入率を得る」ために必要な売価と原価の入力を促し、getBaiKaハンドラーでは「売価を得る」ために必要な原価と値入率の入力を促するスクリプトとなります。

これらのスクリプトを書く上で参考になるのが、先に言及した【スクリプト2の9】に書かれたスクリプトです。
例えば;
ask “put GenKa into me” with “123”
if isnumber(it) then
put it into fld “GenKa”
NeIre
else
select text of fld “BaiKa”
end if

がそれで、この部分の「ask “put GenKa into me” with “123”」や「if isnumber(it) then」、「put it into fld “GenKa”」はそのままこれから書くスクリプトに利用できるものです。この事を念頭において【スクリプト2の11】を変更・追加したものが次の【スクリプト2の12】になります。特に「----------」より下の行が重要な部分になります。

【スクリプト2の12】
on mouseUp
if word 1 of the target is “button” and word 2 of the target is quote & “KeiSan” & quote then
put empty into fld “BaiKa”
put empty into fld “GenKa”
put empty into fld “NeIre”

set the locktext of fld “BaiKa” to true
set the locktext of fld “GenKa” to true
set the locktext of fld “NeIre” to true

set the showfocusborder of fld “BaiKa” to false
set the showfocusborder of fld “GenKa” to false
set the showfocusborder of fld “NeIre” to false

answer “WHAT do you WANT to GET ?” with “GenKa” or “NeIre” or “BaiKa” or “Cancel” as sheet
if it is “Cancel” then
exit to top
end if
if it is “GenKa” then
getGenKa
end if
if it is “NeIre” then
getNeIre
end if
if it is “BaiKa” then
GetBaiKa
end if
else
answer “You MUST push CORRECT button !!” as sheet
end if
end mouseUp

----------

on getGenKa
ask “put NeIre into me” with “50.00”
if isnumber(it) then
put it into fld “NeIre”
else
exit to top
end if

ask “put BaiKa into me” with “246”
if isnumber(it) then
put it into fld “BaiKa”
else
put empty into fld “NeIre”
exit to top
end if

GenKa
end getGenKa

on getNeIre
ask “put BaiKa into me” with “246”
if isnumber(it) then
put it into fld “BaiKa”
else
exit to top
end if

ask “put GenKa into me” with “123”
if isnumber(it) then
put it into fld “GenKa”
else
put empty into fld “BaiKa”
exit to top
end if

NeIre
end getNeIre

on GetBaiKa
ask “put GenKa into me” with “123”
if isnumber(it) then
put it into fld “GenKa”
else
exit to top
end if

ask “put NeIre into me” with “50.00”
if isnumber(it) then
put it into fld “NeIre”
else
put empty into fld “GenKa”
exit to top
end if

BaiKa
end GetBaiKa


これで問2への解法は一応完成という事になります。勿論いつも書いている通りテストが必要ですから、【スクリプト2の12】がキチンと動き、意図した結果が得られるかどうかを自身で確認して下さい。

|

« おばけつぶやき帳 | トップページ | テスト »