変数と有効範囲

変数って何様?

プログラミング言語に馴染みの有る方は、ここは飛ばして下さっても構いません。
そうで無い方は、一読しておいて下さい。

 変数と言う概念は、よく入れ物とその内容物に例えられます。
唐突ですが、ここに「オレンジ」と書いた箱が有ります。
さて、その箱を開けるとオレンジが、10個入っていました。
Logoで記述すると、こんな感じです。

make "orange 10

この「オレンジ」と名付けた箱は、オレンジの個数を持っている入れ物(変数)でした。
確認してみましょう。

print :orange
10

変数の値を調べる場合は、変数名の前に(:)コロン記号を付けます。
このオレンジを、5個食べてみましょう。:-D

make "orange :orange - 5
print :orange
5

10と言う値を持っているオレンジ変数から、5を引きもう一度オレンジ変数に戻しています。
makeコマンドは、変数の名前付けと同時に、値を代入する命令だと言うのが理解出来たでしょうか。
すでに、make "orange 10 で名前付けは終わっていますが、make "orange :orange - 5 で自分自身の値を使い再定義再代入をしている分けです。

変数って何でもアリ?

Logoに言わせれば、何でもありです。
先程定義したオレンジ変数に、別のデータを入れてみましょう。

make "orange "apple
print :orange
APPLE

分け判りませんね。:-(
先程までは、数値だったのに今度は文字列が入りました。しかもオレンジなのにアップルって。
Logoの変数は、なんでも入れられる箱の様な物です。
数値でも文字や文字列それにリストでも配列でも構いません。
他のプログラミング言語(BASIC,PASCAL,Cなど)の様に、変数の型はありません。
したがって、変数がどんな値を保持しているかは、プログラミングするニンゲンの責任になります。
数値を入れなきゃならない変数に、"hogehoge なんてワードを入れたら当然まともにプログラムは動きませんね。
そこで、Logoは変数にどんな値が保持されているか調べる命令があります。

number? :orange  オレンジは数値か?
Result: FALSE    ちがいます。
word? :orange    オレンジはワードか?
Result: TRUE     そうです。
list? :orange    オレンジはリストか?
Result: FALSE    ちがいます。

まだ、他にも調べる命令がありますけど、こんな感じで判るでしょうか。
くれぐれも注意してプログラミングして下さい。>自分の事だけど。

大域変数と局所変数(グローバルとローカル)

to A1
    make "GLOBAL 100
    print sentence "A1.GLOBAL :GLOBAL
    A2
    A3
    print sentence "A1.GLOBAL :GLOBAL
end
         
to A2
    make "GLOBAL :GLOBAL + 100
    print sentence "A2.GLOBAL :GLOBAL
end
         
to A3
    print sentence "A3.GLOBAL :GLOBAL
end

 いきなりサンプルプログラムで申し訳ない。
手続きA1 を実行すると、変数GLOBALの値はどう変わるでしょう。

A1
A1.GLOBAL 100
A2.GLOBAL 200
A3.GLOBAL 200
A1.GLOBAL 200

 この事から何が判るでしょう。そうです、単にmakeで定義された変数は、どの手続きからでも値を参照したり変更したり出来ます。
この変数の事を、大域変数(グローバル変数)と呼びます。
この方法を使えば、手続きに引数を渡さなくても変数の参照や変更が出来るので面倒くさく無いですね。
しかし、手続きA1内で変数GLOBALの値は100を維持したい場合は、どうしたら良いでしょう。

to A1
    make "GLOBAL 100
    print sentence "A1.GLOBAL :GLOBAL
    A2 :GLOBAL
    A3 :GLOBAL
    print sentence "A1.GLOBAL :GLOBAL
end
         
to A2 :GLOBAL
    make "GLOBAL :GLOBAL + 100
    print sentence "A2.GLOBAL :GLOBAL
end
         
to A3 :GLOBAL
    print sentence "A3.GLOBAL :GLOBAL
end
         
A1
A1.GLOBAL 100
A2.GLOBAL 200
A3.GLOBAL 100
A1.GLOBAL 100

 今度は、手続きA2,A3を呼び出す時に引数を付加しています。手続きA2だけで変数GLOBALの値が変わっています。
A3は、参照しているだけなので変わるはずがありません。そしてA1でも値は100を維持しています。
実は、手続きの引数名は、その手続き内だけで有効な局所変数(ローカル変数)だったのです。
グローバル変数と同じ名前の引数名なので、ややこしいサンプルですがローカル変数は手続き内で、その場かぎりの変数ですから同名でもグローバル変数に影響を与えません。

それでは、積極的にローカル変数を使ってみましょう。

to B1
    make "GLOBAL 100
    print sentence "B1.GLOBAL :GLOBAL
    B2
    print sentence "B1.GLOBAL :GLOBAL
end
         
to B2
    local "GLOBAL
    make "GLOBAL "Hello\ World
    print sentence "B2.GLOBAL :GLOBAL
end
         
B1
B1.GLOBAL 100
B2.GLOBAL HELLO WORLD
B1.GLOBAL 100

 手続きB2では、変数名GLOBALをローカル宣言しました。そしてそれに、文字列を代入しています。
B1のグローバル変数GLOBALとは、もはや何の関係もありません。
これでグローバル変数は、Logo全体に有効範囲がありローカル変数は、手続き内だけに有効範囲がある様ですね。
本当でしょうか?

to B1
    local "GLOBAL
    make "GLOBAL 100
    print sentence "B1.GLOBAL :GLOBAL
    B2
    B3
    print sentence "B1.GLOBAL :GLOBAL
end
         
to B2
    make "GLOBAL "Hello\ World
    print sentence "B2.GLOBAL :GLOBAL
end
         
to B3
    local "GLOBAL
    make "GLOBAL 200
    print sentence "B3.GLOBAL :GLOBAL
end
         
B1
B1.GLOBAL 100
B2.GLOBAL HELLO WORLD
B3.GLOBAL 200
B1.GLOBAL HELLO WORLD

 ありゃりゃ、おかしな結果になりました。
手続きB1で変数GLOBALを、ローカル宣言したはずです。それなのに、B2ではB1のローカル変数を変更出来てしまいました。
B3では、ローカル宣言をしていますので影響はありませんね。
B2では、ローカル宣言をして、、、、、いないですね。

B2
B2.GLOBAL HELLO WORLD
print :global
HELLO WORLD
make "global "good\ bye
print :global
GOOD BYE
         
B1
B1.GLOBAL 100
B2.GLOBAL HELLO WORLD
B3.GLOBAL 200
B1.GLOBAL HELLO WORLD
print :global
GOOD BYE

 今度は、B2だけ実行してみました。その後、変数GLOBALを参照してみるとHELLO WORLDが入っています。
その変数をListenerウインドウから直接変更してみました。間違いなくグローバル変数です。
そして、もう一度手続きB1を実行します。グローバル変数を調べてみると、、、、、変わっていなーい。
なんでぢゃあああぁぁあ!B-(
この機能が、動的有効範囲(ダイナミック・スコープ)です。
手続きを呼び出す順番により、ローカル変数の参照になったりグローバル変数の参照になったりします。

to C1
    local "LOCAL
    make "LOCAL 100
    print sentence "C1.LOCAL :LOCAL
    C2
    print sentence "C1.LOCAL :LOCAL
end
         
to C2
    print sentence "C2.LOCAL :LOCAL + 100
    C3
end
         
to C3
    print sentence "C3.LOCAL :LOCAL + 200
end
         
C1
C1.LOCAL 100
C2.LOCAL 200
C3.LOCAL 300
C1.LOCAL 100

 手続きC2,C3では、変数を宣言していません。でも、C1から呼び出しているので同名の変数は上位の変数を、参照するダイナミック・スコープ機能が働くので、ちゃんとC1のローカル変数を参照する事が可能です。
C3はC2から間接的にC1から呼び出されていますので、遡っての変数の参照が出来ていますね。
試しに手続きC2だけ実行してみましょう。

C2
:LOCAL is not a name
at:   C2
line: PRINT SENTENCE "C2.LOCAL :LOCAL + 100

 エラーになりました。LOCALって名前は知らないって言ってます。:-)
ローカル変数は、グローバル変数の様にプログラムの実行後も残りませんからLogoが、判らないって返してくるのは当然なのです。
この機能をうまく使えば、グローバル変数は使わずにプログラムを、書く事が出来ますね。
Logoの、ほとんどの手続きは引数を使っての呼び出しをしています。引数は、暗黙的にローカル変数です。
手続き内でローカル宣言された変数は、明示的なローカル変数ですね。
そして、ダイナミック・スコープ機能。
この3つの事を理解すれば、エレガントにプログラムを書く事が出来ます。:-D
グローバル変数を、大量生産して分けの判らないプログラムを書かない様に注意しましょう。