エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

Ioが面白い・その0 の その3 柔軟運動

2日目。

7つの言語 7つの世界

7つの言語 7つの世界

ループ

while

第1引数の値が真のばあい、第2引数を評価します。式の値は第2引数の最後の値です(ここでは最後のi = i + 1の結果の値)。

Io> i := 1
==> 1
Io> while(i < 10, "hoge" println; i = i + 1)
hoge
hoge
hoge
hoge
hoge
hoge
hoge
hoge
hoge
==> 10

第2引数が評価されなかったばあいの式の値はnilです。
上のwhileをそのままもう一度実行したばあい。

Io> while(i < 10, "hoge" println; i = i + 1)
==> nil


「引数」と書きましたが、実のところwhileObjectオブジェクトのメソッドとして実装されています
上記ではオブジェクトの外でwhileを使っていますが、そのばあいはマスター名前空間のオブジェクトであるLobbyにメッセージが送られます。

for

第1引数にカウンタ名、第2引数に初期値、第3引数に終了値を指定します。
第5引数がないばあい、第4引数を初期値から終了値のあいだまで評価します。

Io> for(i, 1, 9, i println)
1
2
3
4
5
6
7
8
9
==> 9

第5引数があるばあい、第4引数は増分をあらわし、第5引数を評価します。

Io> for(i, 1, 9, 2, i println)
1
3
5
7
9
==> 9

Ioでは余分な引数は無視されるようです。
次のように書くと第5引数は「i println; "hoge" println」ですが、

Io> for(i, 1, 3, 2, i println; "hoge" println)
1
hoge
3
hoge
==> hoge

次のように書くと第5引数は「i println」で、第6引数になる「"hoge" println」は無視されます。

Io> for(i, 1, 3, 2, i println, "hoge" println)
1
3
==> 3

コンマとセミコロンを間違えると予想外の結果を引き起こします。

==> hoge
Io> for(i, 1, 3, i println; "hoge" println)
1
hoge
2
hoge
3
hoge
==> hoge
Io> for(i, 1, 3, i println, "hoge" println)
3
hoge
==> hoge

慣れないとちょっと怖い。

loop

ループにはもうひとつ、終了条件のないloopがあります。Ctrl+Cで強制終了してください。

Io> i := 1
==> 1
Io> loop(i println; i = i + 1)
1
2
3
4
(以下略)

条件式

ifメソッドです。
第1引数が真ならば第2引数を評価し、偽ならば第3引数を評価します。

Io> a := 1
==> 1
Io> b := 2
==> 2
Io> if(a < b, "TRUE" println, "FALSE" println)
TRUE
==> TRUE

式の値は最後に評価された値です。


面白いのは、ifメソッドを実行すると、まず第1引数が評価され、その結果によって第2引数か第3引数が評価されます。
C++Javaでは、まず各々の引数が評価されて、そのあとに、それらの結果をもらってメソッドが実行されます。
Ioでは、引数はメソッドにそのままの状態で渡されて、引数をいつ評価するかはメソッドの中で決めることができます。いわゆる遅延評価というやつです。


上記の書き方の他に、C++javaのような書き方もできます。

Io> a := 1
==> 1
Io> b := 2
==> 2
Io> if(a < b) then("TRUE" println) else("FALSE" println)
TRUE
==> nil

まずifメソッドが実行され引数を評価し、その真偽を返します。上記のばあい真なのでtrueを返します。
次にtrueオブジェクトのthenメソッドが実行されます。truethenは引数を評価するので"TRUE" printlnが評価され、文字列が表示されます。このときの戻り値はnilです。
最後にnilオブジェクトのelseメソッドが実行されます。nilelseは引数を評価せずnilを返します。


真偽が逆になったばあい。

Io> a := 1
==> 1
Io> b := 0
==> 0
Io> if(a < b) then("TRUE" println) else("FALSE" println)
FALSE
==> nil

まずifメソッドが実行され引数を評価し、その真偽を返します。上記のばあい偽なのでfalseを返します。
次にfalseオブジェクトのthenメソッドが実行されます。falsethenは引数を評価せずfalseを返します。
最後にfalseオブジェクトのelseメソッドが実行されます。falseelseは引数を評価するので"FALSE" printlnが評価され、文字列が表示されます。このときの戻り値はnilです。

なので。
elseがないばあい、全体では真のばあいはnilが、偽のばあいはfalseが返ります。

Io> if(true) then("TRUE" println)
TRUE
==> nil
Io> if(false) then("TRUE" println)
==> false


ここまで読み解いてみると。「ifっていらなくね?」という疑問がわきますが。
そのとおりです。

Io> (a < b) then("TRUE" println) else("FALSE" println)
TRUE
==> nil

もっとも。読み手を混乱させる効果ぐらいしがなさそうなのでやめておいたほうがよさそう。


その替わりに。Smalltalk風の書き方ができます。

Io> (a < b) ifTrue("TRUE" println) ifFalse("FALSE" println)
TRUE
==> true
Io> (a > b) ifTrue("TRUE" println) ifFalse("FALSE" println)
FALSE
==> false


…繰返しと条件分岐の説明だけでこんなにかかるとは思わなんだ。
長くなったので。次回につづく。