#ありがとうございます。flusherを指定するとうまくいきました。
#(use gauche.generator)
(use rfc.http)
(use gauche.vport)
(define (vport-generator proc)
(generate
(^(yield)
(let1 oport (make <virtual-output-port>
:puts
(^x
#?= x
(yield x)))
#?= oport
(proc oport)
) ) ) )
(define g (vport-generator
(^p
#?= p
(http-get "www.google.com" "/"
:sink p
:flusher (^ arg #t) )
) ) )
(define (main args)
(do-generator (x g) (debug-print x) ) )
#上記コードだと、確かにyieldは読んでいるはずですが、generatorは空なのです。この指定は適切ではないのでしょうか。
#http-getからポートを作る手段としてこのようなgeneratorを作ってみたのです。
#oportから他の手続きに渡せる形のinput portをつくる適切な道筋が思いつかないのです。
#(define (vport-generator proc)
(generate
(^(yield)
#?= yield
(let1 oport (make <virtual-output-port>
:puts
(^x
#?= x
(yield "foo")
(yield x)))
#?= oport
(yield "bar")
(proc oport)
) ) ) )
#(yield "bar")をコメントにすると #?= xが実行されてダンプされるのですが、コメントにしなければ#?= xが実行されないのです。
#gosh> (g)
#?=yield
#?- #<closure (generate cont #f #f)>
#?=oport
#?- #<virtual-output-port #f 0x8ff9850>
"bar"
#(yield "bar")をコメントにすると↓
#gosh> (g)
#?=yield
#?- #<closure (generate cont #f #f)>
#?=oport
#?- #<virtual-output-port #f 0x9004e00>
#?=p
#?- #<virtual-output-port #f 0x9004e00>
#?=x
#?- "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text ...
#?=x
#?- #*"<!doctype html><html itemscope=\"itemscope\" itemtype=\"ht ...
#?=x
#?- "40304,40330\",kCSI:{e:\"17259,39034,39418,39515,39579,39677, ...
#?=x
#?- "ad=h\")return 0;c=b}_gjwl.href=\"/search?\"+a+\"&cad=h\";ret ...
#?=x
#?- "\"focusout\");var f=c,c=function(a){a||(a=window.event);retu ...
#?=x
#?- "c.d=g;c.c&&(0<c.c.length&&g(c.c),c.c=h)},G=[\"google\",\"jsa ...
#?=x
#?- "ne}a.gb3:hover{text-decoration:none}#ghead a.gb2:hover{color ...
#?=x
#?- #*"ccc}.lst:focus{outline:none}#addlang a{padding:0 3px}.gac_ ...
#?=x
#?- #*"p/nwshp?hl=ja&tab=wn\">\x83j\x83\x85\x81[\x83X</a> <a clas ...
#?=x
#?- #*"ign=\"top\"><td width=\"25%\"> </td><td align=\"cente ...
#?=x
#?- #*"/ja/services/\">\x83r\x83W\x83l\x83X \x83\\\x83\x8a\x83\x8 ...
#?=x
#?- #*"3lFqRj_rDg.en_US./d\\x3d1/rs\\x3dAItRSTNd2xM7N-7jiWER5XvKU ...
#?=x
#?- #*"-84px\",\"nlpp\":\"-153px -70px\",\"utp\":false},77:{},254 ...
#?=x
#?- "timers.load,google.kCSI)}if(window.addEventListener)window.a ...
#<eof>
#↑ジェネレータは空になります。
#generateに渡す関数が実行を終えたらその時点でジェネレータはおしまいです。(yield "bar")があればそこで実行が(ジェネレータが呼び出されるまで)サスペンドされるので、その場合はoportのputs手続きが呼ばれるまで(^(yield)...)が生きてるわけですが、それがないとputs手続きが呼ばれる前に(^(yield)...)の実行が終了してしまうのでジェネレータはすぐに空になっちゃいます。
#(yield "bar")が生きているときには、putsそのものが実行されていないように見えるのです。(yield "bar")を殺したときには、putsが実行されているようですが、puts内のyieldが実行(?)されていないように見えるのです。
#やりたいことはコルーチンなわけですが、virtual portは一回Cのスタックを跨ぐため、(限定)継続を使ったコルーチンはどっちにせようまく動作しません。こういうのはどう書くのがいいかなあ。マルチスレッドにしてキューを間にはさむのが一番手軽だと思います。
#そういうことだったのですか>Cのスタック。 勉強になりました。ありがとうございます。
#http-getから入力ポートをつくってcall-with系手続きを書く方法となると、やはりマルチスレッドを使うということになるのでしょうか?
#ああ、with-input-from-uriを作るにはそれを考えないとならないなあ。ライブラリにするならできればマルチスレッドを要求するのは避けたいですね。
#完全なコルーチン (スタック2本を乗り換える) ではなく、一方をコールバックで書く (状態をスタックではなく環境に保持しといて、virtual portのハンドラからコールバックを呼び出す) ようにすればできないかな。
#(use rfc.http)
(define (main args)
(debug-print (http-get "www.google.com" "/"
:sink (^ x (debug-print x) )
:flusher (^ _ #t) )
) )
#sinkに手続きを渡せると書いてあったのですが、これはエラーになるのですね。
#Scheme:初心者の質問箱:log00
http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3a%e5%88%9d%e5%bf%83%e8%80%85%e3%81%ae%e8%b3%aa%e5%95%8f%e7%ae%b1%3alog00#H-5d19io
#「渡せるようにしたらどうかな」ってアイディアが書いてあるだけで「渡せる」と書いた覚えはないのだけれどどっかに書いてあります? そのへんのアイディアがreceiverとして具体化されたって流れじゃなかったかなあ。
#そうでしたか。了解です。
#むー、コールバックをやってみたんだけど、rfc.httpのreceiverにわたされるretrieverが限定継続を使っちゃってるから、「virtual portのハンドラ内でreceiverを呼び出す」ってところでC stack境界の制限を踏んじゃうっぽい。こうなるとreceiverのAPIを考え直した方がいいかも。
#なんか思い出してきた。「with-input-from-uriを素直に書けるように」receiverの仕様を決めたかったので、まだオフィシャルにしてないんだった。
#しかしこうなるとポートI/OでC stackを必ずまたぐという仕様もどうにかしたいなあ (もちろんCの呼び出しはあるんだけど、その先で一旦suspendしたい事態が生じた場合に、VMまでトランポリンさせる方法が欲しい)。今のだとポートをnon blockingにして入力がなければスイッチする、というのもやりにくい。
##read-blockが(retr)が返したサイズを読む前に終わる場合にどうするかということでした。
##gosh> (define x (http-get-generator "www.yahoo.com" "/"))
x
gosh> x
#<closure (generate generate)>
gosh> (x)
#?=x
#?- #*"<!DOCTYPE html>\n<html lang=\"en-US\" class=\"y-fp-bg y-fp ...
*** HTTP-ERROR: bad line in chunked data: " <meta name=\"description\" content=\"Welcome to Yahoo!, the world's most visited home page. Quickly find what you're searching for, get in touch with friends and stay in-the-know with the latest news and information.\">"
Stack Trace:
_______________________________________
0 (receive-body in code rep-headers receiver)
At line 643 of "/usr/local/share/gauche-0.9/0.9.3.3/lib/rfc/http.scm"
1 (with-error-handler (lambda (e) (let ((e e)) (%guard-rec e e (else ...
[unknown location]
2 (request-response method conn host request-uri sender receiver `(: ...
At line 245 of "/usr/local/share/gauche-0.9/0.9.3.3/lib/rfc/http.scm"
3 (proc (^ (value) (shift k (set! cont k) value)))
At line 400 of "/usr/local/share/gauche-0.9/0.9.3.3/lib/gauche/generator.scm"
4 (eval expr env)
At line 173 of "/usr/local/share/gauche-0.9/0.9.3.3/lib/gauche/interactive.scm"
#ふーむ、全部読めてないっぽいですね。限定継続のバグを踏んだかな。
#(yield x)の直前の#?= xは実行されて、内容が表示されているので,yieldの飛び先が問題なのかなとか思いました。
#私もそこを疑っています。限定継続が互い違いに呼びあっているので。
#むー、shiftは動的に直近のresetまでを切り取るわけだから、限定継続の動作としてはこれが正しいのかな。