Tcl使おうぜ
Tcl/Tkは、90年代に流行したスクリプト言語だ。私はTclが気に入っていてよく使うのだが、周りには使っている人が誰もいない。情報もほとんどないので、そもそも使い始めようと思わないかもしれない。しかしGUIベースのちょっとしたプログラムを作るには大変便利なものなので、ちょっと紹介してみようかな。
#究極のおまけ言語
Tclなんか使ったことない、という人のPCにもすでにTcl/Tkがインストール済みであることが多い。さまざまなプログラミング言語やアプリケーションのグラフィックライブラリがわりについてくることが多いからだ。私が知っているだけでも、R, Python, Maxima などにおまけとして付いてくる。これらの言語を使っている人はディレクトリを掘ると出てくるので探してみて欲しい。
特徴
Tclは非常に癖のある言語だ。その特徴は次のようになる。
- 言語の機能はほとんどすべて「コマンド」として実現されている。プログラムの見た目はshell scriptにそっくり。コマンドなので、行の概念がある。
- 言語が扱うデータは、すべて(見た目は)文字列として表現されている。リストは空白で区切られた文字列であり、プログラム自体もリストである。(実際は効率のために内部表現になっている)
#文字列とリスト
特に変態なのが、{ }
による文字列だ。文字列の表現には、次の3種類がある。
- 文字列の両端に何もつけずに書く。たとえば
abc
は文字列である。文字列の間に空白を含めることはできない。$var
のような変数置換を行う。 - 文字列の両端を
"
で囲む。"abc def"
は1つの文字列である。文字列に空白が含まれても良い。変数置換が行われる。 - 文字列の両端を
{ }
で囲む。{abc def}
は1つの文字列である。文字列に空白が含まれても良い。変数置換は行われない。
{ }
による文字列の中に、再帰的に{ }
を含めることができる。例えば、{a {b c} d}
という文字列の場合、1文字目はa(最初の{
は区切り文字なので文字列に含まれない)、2文字目は空白、3文字目は{、4文字目はbといった具合。また、{ }
による文字列には空白だけでなく改行を含めることができる。例えば
set x {abc
def
ghi}
という具合だ。
文字列はリストとして解釈することもできる。リストは空白で区切られた文字列であり、リストの中にリストを含めることができる。
-
{a b c}
は"a","b","c"という3つの文字列からなるリスト -
{a {b c} d}
は"a","b c","d" という3つの文字列からなるリスト -
{a {b {c d}} e}
は"a","b {c d}","e"という3つの文字列からなるリスト
「文字列はリストでもある」というのがTclの大きな特徴であり、わかりにくい点でもある。ちなみに空白で区切られた文字列がリストなので、"ab cd ef"もリストである。
#プログラムを書いてみる
文字列の話も飽きたので、プログラムを書いてみよう。
puts "Hello,world"
数を数えることもできる。
for {set i 0} {$i < 10} {incr i} {
puts "Hello, world $i"
}
Tclでは変数への値の代入はset
を使う。
set 変数名 値
値を省略すると、変数の値を返す。
Tclには、言語の機能としての「式」はない。値の計算をするのはexpr
というコマンドである。
set i 10
expr $i+2 ;# 12
ここでの$i+2
は単なる文字列で、変数置換により10+2
という文字列になる。それをexpr
コマンドが解釈して12という値を返す。
変数の値を±1する処理はプログラムのあちこちに頻出するが、それにいちいちexpr
を使っているとめんどくさいので、変数の値に定数を加えるincr
コマンドがある。incr
コマンドは、第1引数に書いた変数の値を+1する。第2引数を書くと、その値を変数に加える。
set i 0
incr i
puts $i ;# 1
ということで、先ほどのfor
は次のような形をしている。for
もコマンドであり、4つの引数を取る。それぞれの引数はリストである。{ }で囲まれているので、普通の言語でのブロックのように見えるが、Tclにはブロックはない。単なる文字列/リストである。
for 初期化 継続判定 更新 処理
これは次のような動作をする。
- 「初期化」リストを評価する。
- 「継続判定」リストを
expr
の引数として実行。値が0ならば終了。 - 「処理」リストを評価する。
- 「更新」リストを評価する。
- 2.から実行する。
for
はコマンドなので、
for {set i 0} {$i < 10} {incr i}
{
puts $i
}
のように書くとエラーになる。コマンドは行で終了するので、上の例では引数が3つしかないからだ。
for {set i 0} {$i < 10} {incr i} {
puts $i
}
のようにすると、for
の引数は4つであり、4つ目の引数である文字列の中に改行文字が含まれる。
その2に続く。