Gauche > Archives > 2012/03/10

2012/03/10 11:32:04 UTCshiro
#
sumimさんの「普通の言語ではどうやっても真似できない変態FizzBuzzをSqueak Smalltalkで」http://d.hatena.ne.jp/sumim/20120309/p1 を見て、「戻り値がどう使われるか」によって動作を変えているのが、以前Ruiさんが作った継続のarityで動作を変えるやつ http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3A%E7%B6%99%E7%B6%9A%E3%81%AEarity みたいだなあと思った。
#
そんでぼんやり考えてたら、今のVMだと継続のarityはもっとずっと簡単に実装できることに気づいた。継続フレームを変更しないでも、Scm_VMCallCCの中で継続フレームの中身を調べてやれば次に実行するインストラクションがわかるので、そこから継続のアリティがわかる (こともある)。
#
勢いで書いちゃったんだけど、wilikiの議論にあるようにあてにできない情報なので、このままでは何とも使いようが無いかなあ。ただ、ランタイムに継続が期待している情報を色々得られるというコンセプト自体はおもしろい。
#
発展させると、静的型言語に比べて動的型言語が不利な「戻り値の型の情報を利用できない」という点をカバーする何か、にはならないだろうか。むむむ。とはいえ一旦ジェネリックに受けちゃうと取れる情報が無くなっちゃうってのはいかんともしがたいか…
#
現在のHEADに対するパッチはこれ https://gist.github.com/2011209 ちょっと余分なのも入ってる。
2012/03/10 20:43:52 UTCRui
#
まずそのWikiが8年前というのにびっくりしました。時間のたつの早すぎ。
#
その後もたまに思い出して考えてみたりしたけどそこに書いてある以上のことは特に考えつかなかったですね
2012/03/10 20:59:28 UTCshiro
#
arityを取れること自体は決定的ではないんですが、continuation subrがarityをちゃんと持ってると呼び出した時に引数をリストにパックしないで良いので若干性能的に有利かもしれません。(上のパッチでは、まだdynamic handlerを呼び出すために引数を保存する際にパックしちゃってるので意味ないですが、このパッキングをなるべく避けられれば。)
#
あと、RECEIVE系インストラクション以外は「正確に1個の値を必要とする」か「0または1個の値でok(どうせ捨てる)」か、なので、インストラクション定義にその情報を追加すれば、今はRECEIVE以外でさぼってる返り値の個数のチェックを自動生成できるかもなあ、とか。その情報はcontinuation subrにアリティを追加するのにも使えますし。
2012/03/10 21:18:24 UTCRui
#
それはコンパイル時に外側のフォームがいくつの返り値を期待しているかという情報を持ちまわって、生成するVMインストラクションにその情報を埋め込んでおく、ということですか?
2012/03/10 21:21:06 UTCshiro
#
いえ、実行時にスタックを調べて、次に実行されるのがPUSH-*であれば1個の値を期待している、等とわかる、ということです。RETであればさらに継続フレームをたどる。常に判断可能とは限りませんが、だいたいのケースでわかるんじゃないかなあ。
#
C Continuationが間に挟まってるとわからなくなりますが。
2012/03/10 21:22:46 UTCRui
#
ああなるほど、おもしろいですね。C continuation以外でわからなくなるケースはありますかね。
2012/03/10 21:24:30 UTCshiro
#
あとすぐ思いつくのは、Scm_Eval等から呼ばれてる場合(boundary continuation frameに当たった場合)かなあ。
2012/03/10 21:29:04 UTCshiro
#
Schemeから呼ばれてる場合は基本的にわかりそうですね。
2012/03/10 21:34:43 UTCRui
#
そういう気がしますね。
2012/03/10 21:37:19 UTCshiro
#
partial continuationで切り取られちゃうとわからないけど、その場合はそもそも継続チェインが途切れてるわけだからなあ。
2012/03/10 22:02:54 UTCRui
#
継続のアリティがわかったとして役立つケースがあるかどうか考えてみたんですが、追加的な情報を2番目の返り値で返す関数で、2個目の返り値が不要なら計算したくない(コストが高いとか)というとき、2番目の引数がreceiveされるかどうかを調べて実行時に最適化を行う
#
というのを思いついたんですがいまいち具体例は思いつきませんねぇ。
2012/03/10 22:15:35 UTCshiro
#
ふーむ。機能としては考えられるけど、Scheme的には「2つの値を返す関数の結果の1つ目だけ受ける」って書き方が許されないのでScheme仕様準拠なプログラムではそもそも使えないなあ。(values-refみたいにreceiveで受けて明示的に捨てるのは書けるけど、それだと2番目の値も計算されちゃうし…)
2012/03/10 22:22:29 UTCRui
#
まあSchemeの仕様の範囲内で書けないのはそうなんですが、2つ値を返して1つ目だけ受ける(2つ目は黙って捨てられちゃう)、というのと、1つの値だけが期待されているときは1つの値を返し2つの値の場合は2つの値を返す(期待されている返り値の個数と常にマッチしている)、というのは意味的には違わないですか?
2012/03/10 22:32:44 UTCshiro
#
そう考えればいいのか。期待してる値がわからない (#<arity-at-least 0>のとき) は呼び出し側が責任持ちますよ、ってことで。「1個または2個の引数を取る手続き」が許されるなら、その逆も考えられるわけだね。
2012/03/10 23:15:35 UTCshiro
#
アリティだけじゃなくて、「戻り値に期待されている型」でディスパッチできたらどうだろう。そしたら http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3AExplicitMonad みたいなことをせずともモナドが使える。ただ、やっぱり「型が常にわかるとは限らない」ってとこが問題になるかなあ。