Gauche > Archives > 2014/02/14

2014/02/14 06:42:59 UTCshiro
#
で、pegちょっと仕事で使うんでまたいじってるんだけど、文字列、文字、文字セットのリテラルをparserにリフトするのに今は ($string "word")とか($one-of #[a-z])とかしてるけど、これを「parserを期待してるところにこれらのオブジェクトが来たら暗黙のうちにparserに変換する」って機能を入れようかどうか迷ってる。
#
前にも何度か考えたことがあって、結局やってないので何かデメリットを思いついたと思うんだけどそれが何だったか思い出せない。今考えて思いつくデメリットは、式の型がわかりにくくなって混乱する、くらいかなあ。
2014/02/14 06:51:23 UTCshiro
#
ああ、パーザ生成をインライン展開する際に明示されてる方がいいってことだったかなあ。
2014/02/14 10:21:39 UTCshiro
#
pegのコードを見直してるが、何でAPIをこうしたのか覚えてないところが結構あるなあ。やっぱりドキュメント重要だ。
2014/02/14 18:23:14 UTCshiro
#
ふむ、parser.pegのapiはparsecに影響を受けていたんだな。だけどGauche的には本来のPEGに戻った方が使い勝手が良い気もする。$tryを明示させるのとか、parsecは性能のためにそうしてるんだけど、今のGaucheの実装だと$orの中にバックトラックを組み込んでも大して性能変わらないように思う。
2014/02/14 19:18:06 UTCshiro
#
Parsecでtryを明示しないchoiceは、実質cut operatorをはさんでいるのと同じことになる。cutするとそれ以前のバックトラックスタックやメモワイズを忘れて良いので効率が良くなる。 (cf. http://ialab.cs.tsukuba.ac.jp/~mizusima/publications/paste513-mizushima.pdf )
#
ところがGaucheの今の実装では、$orで最後以外のchoiceは非末尾で呼び出されるから、入力を消費して他の選択肢を試す必要がないとわかってもスタックは使われたままで、cutのメリットがない。
#
そんでtryは入力リストを掴んでおくだけだから、orに追加されるオーバヘッドはわずかなものだ。だから現状でorとtryを分ける意味は無いといってよい。
#
cutでバックトラックスタックをクリアする、というふるまいを今のやり方で実現するなら、orで継続をセーブしといてcutした時点で戻り先をセーブした継続にするってことになる。だが継続のセーブは軽くはない。
#
それならいっそ自前でバックトラックスタックを管理して、パーザ手続きの実行はトランポリンでやるか? 結構大きな書き直しになりそうではあるが…
2014/02/14 23:34:18 UTCshiro
#
結局のところ、parsec式のパーザコンビネータは、モナド+遅延評価の枠組みが既にあるところに載せるのは効率が良いけど、Schemeのように (1)モナドからいちいち作らないとならない (2)eagerな評価機だとcutでスタックを捨てるのにcall/ccが要る、ってんであまり嬉しくないのかもしれん。
2014/02/14 23:39:07 UTCshiro
#
いや、eagerな評価機でも再帰でパーザを呼ばずにcpsかトランポリンにすればcall/ccは要らないか。
#
どっちにせよパーザを組み合わせる時に必ず$doや$liftを経由するなら、呼び出しの詳細は隠蔽できるのだから、今の Parser : [s] -> Status,Value,[s] の形にこだわる必要はない…