Iconのプログラムでは、generatorをよく使います。その動作確認のために generator
の出力を書き出すことがよくあります。
例えば、Iconの組込 generatorに、数を順に発生させる seq()がありますが この先頭
の 10個の書き出しは、こんな風になります。
-----^ G_TEST1.ICN ( date:03-11-02 time:00:27 ) ------------<cut here
####################
# generatorの出力を一行に書き出す
####################
# g_test1.icn Rev1.1 2003/11/02 風つかい
# 1,2,..,10 -> "1 2 3 .. 10"
# This file is in the public domain.
procedure main()
s := " " # 間隔文字
n := 0 # 先頭検出用
# ↓ 1,2,..と数を発生する generator
every ss := seq() \10 do { # \10は、generatorの生成数を 10個に限定
if n > 0 then writes(s,ss) # 先頭でなければ、生成数と間隔文字を出力
else writes(ss) # 先頭なら、生成数を出力
n +:= 1
}
write() # カーサ戻し
end
-----$ G_TEST1.ICN ( lines:19 words:72 ) -------------------<cut here
出力は、こんな風になります。
-----^ G_TEST1.1 ( date:03-11-02 time:00:07 ) --------------<cut here
1 2 3 4 5 6 7 8 9 10
-----$ G_TEST1.1 ( lines:1 words:10 ) ----------------------<cut here
今まで、generatorの出力の書き出しは、main()の中でやっていました。
度々ですので、generatorの書き出し procedureを作ってみようと思いました。
で、単純にこんな風にしてみました。
-----^ G_TEST2.ICN ( date:03-11-02 time:00:27 ) ------------<cut here
####################
# generatorの出力を一行書き出す
####################
# g_test2.icn Rev1.1 2003/11/02 風つかい
# 1,2,..,10 -> "1 2 3 .. 10" を、書き出し procedureを使って、出力しようと
# したが...
# This file is in the public domain.
procedure main()
# ↓ 1,2,..と数を発生する generator
g_out(seq() \10) # \10は、generatorの生成数を 10個に限定
end
procedure g_out(gen,s)
/s := " " # 間隔文字
n := 0 # 先頭検出用
every ss := gen do {
if n > 0 then writes(s,ss) # 先頭でなければ、生成数と間隔文字を出力
else writes(ss) # 先頭なら、生成数を出力
n +:= 1
}
write() # カーサ戻し
end
-----$ G_TEST2.ICN ( lines:23 words:80 ) -------------------<cut here
g_outという procedureを作って、この引数に generatorを指定すれば、
generatorの出力を取り出して、一行に書き出してくれる予定です。
でも、動かしてみますと、あれれ。
-----^ G_TEST2.1 ( date:03-11-02 time:00:07 ) --------------<cut here
1
2
3
4
5
6
7
8
9
10
-----$ G_TEST2.1 ( lines:10 words:10 ) ---------------------<cut here
一行に書き出すつもりが、generatorの各々の出力が、一行ずつに出力されます。
procedureの引数に generatorを指定しても問題ないと試してあるし、なして〜?
悩んだあげく、私の知識では解決できそうにありません。 そこで、
Iconの拡張版 Uniconの開発プロジェクト
http://unicon.sourceforge.net/index.html
のメーリングリストで、質問してみたところ、親切に解説して頂きました。
g_out(seq() \10) で、g_outの引数に seq() \10 を 引き渡したつもり なのですが、
g_outの引数に渡っているのは、seq() \10 ではなく seq() \10 が生成したデータ
とのこと。
seq() \10 が生成するのは、1 〜 10 の数ですが、それが 順に 10回 g_outに渡る
のだそうです。
そこで、g_outの every ss := gen do .. で、seq() \10 から、順にデータを引き
出しているつもりが、実際は データが 1個しかない状態とのこと。 それが 10回
繰り返されるそうです。
g_outは、生成データが 1個だと、それをそのまま書き出しますので、10個のデータ
が順に書き出されることになります。
「procedureの引数に generatorを指定できる。」というのは、正しいのですが、
動きとしては、解説のようになるそうです。
正確には、「procedureの引数に 式(expression)を指定できる。」だそうですが。
ということで、データだけ渡るのがマズイのなら、procedureを渡せばよいだろうと
作ったのが、次の procedureです。
-----^ G_TEST3.ICN ( date:03-11-02 time:00:46 ) ------------<cut here
####################
# generatorの出力を一行に書き出す
####################
# g_test3.icn Rev1.1 2003/11/02 風つかい
# 1,2,..,10 -> "1 2 3 .. 10" の書き出し
# procedureを引数として渡すやり方
# This file is in the public domain.
procedure main()
# ↓ generatorを g2sの引数にして渡す
write(g2s(seq,,10)) # また procedureの引数も g2s渡す
end
####################
# generatorの出力書き出し procedure
####################
# arg [1]: procedure(generator)
# [2]: list(引数)
# [3]: generatorの出力生成数
# [4]: 間隔文字
# value : (none)
procedure g2s(gproc,Larg,n_limit,s)
/s := " " # delimiter
/Larg := [] # argument of gproc
s1 := "" # 足し込み用 空文字列
# ↓生成数指定が無いか?
every n := if /n_limit then gproc ! Larg # 生成数指定が無ければ
else gproc ! Larg \n_limit # あれば
do s1 ||:= (n || s) # s1に足し込み (nは、自動的に文字列へ変換される。)
return s1[1:-*s]
# ↑最後に余分についている間隔文字の手前まで
end
# 補足
# gproc ! Larg は、procedureの引数を listで与える記法。
# 例えば、write("ABC","DEF") は、write ! ["ABC","DEF"] とも書ける。
# 部分文字列 s[1:-1]の -は、位置を最後から数えるやり方。
# 例えば、"ABCD"[1:-1]は、最初から最後の手前までの "ABC" となる。
-----$ G_TEST3.ICN ( lines:38 words:139 ) ------------------<cut here
直接書き出すと、汎用性が減りますので、文字列を作成するようにしてみました。
結果は、こうなります。
-----^ G_TEST3.1 ( date:03-11-02 time:00:39 ) --------------<cut here
1 2 3 4 5 6 7 8 9 10
-----$ G_TEST3.1 ( lines:1 words:10 ) ----------------------<cut here
メーリングリストでは、そういうやり方もあるけど、Co-Expression を使うのが
いいよ と教えて頂きました。 それは次回に。
尚、Iconは元々テキスト処理用に開発されましたが、Unicon Projectは、更に
Graphic処理、Network処理、OO(オブジェクト指向)、等の拡張のためのプロジェクト
です。
風つかい(hshinoh@...)
IconのWWWは、 http://www.cs.arizona.edu/icon/
UniconのWWWは、http://unicon.sourceforge.net/index.html
BGM: Round About Midnight / 杉本喜代志