ryoakg(2011/06/26 03:38:35 PDT) 元々やりたかった事は、
アドレスやポートの情報 → socket
の hash-table を作って、まだ socket が入ってなかったら(主に初めて通信する相手)、socket を作って hash-table に入れる。
一定期間通信していなかったりしたら、hash-table-delete!。socket-close もする。
という様な事です。hask-table のキーとしてこれを使うのが妥当かどうかは、よく分かりませんが、元から入っているものなので、自分で同じ様なものを作るよりも良いかと思っただけです。
でも一方で、これは Unix から来たもので、元々 Unix でもそういう使い方をしているか? といえばそうでもない気がするので、なるべくC言語のAPIをそのままラップしてそれ以上の事は、もっと外側でやるというポリシーに反するのかもしれません。
でも、その辺りを律儀にやって新たなレイアを作るのも、煩わしい気もします。
私としては、取れない情報があるわけではないので困り度は低いです。
SCM_DEFINE_BUILTIN_CLASS を使っているところだけ、ある程度見ましたが compare が入っていないものは多い様だったので、ひとつひとつ見ていくとアレもコレもとなってしまう気もしました。
また、ScmClassCompareProc の 3つ目の引数の equalp の意味が分かりませんでした。(sort などするときの全順序な場合とそうでない場合?)
object-equal? メソッドでできないかな、
とやってみたらできませんね。compareが入ってないとobject-equal?も呼ばれないのか。
object-equal? を呼ぶようにしてしまうという手がひとつありますが、
この問題に関してはハッシュテーブルで比較関数とハッシュ関数をカスタマイズできるように
する、という方が根本的な解決になりそうだと思います。
(object-equal? のカスタマイズはグローバルな効果を持つので、
本来はクラスを提供する人が同時に提供すべきで、ユーザが後付けで定義するものではない。)
ryoakg2011/01/09 20:40:46 PST 言いたい事が2点ありますが、分けて書いても、混ぜて書いても、うまく書けそうにないですが、とりあえず混ぜて書きます。
現状(rev7345)
gosh> (unpack "VVV" :input (open-input-string "")) (#<eof> #<eof> #<eof>)
の様に入力が半端な部分だけに #<eof> が入る様になっている。これを #<eof> だけを返す様にして欲しい(リストに入れない)。
gosh> (unpack "VVV" :from-string "aaaabbbbcc") (1633771873 1650614882 #<eof>)
の様に入力が半端な部分だけに #<eof> が入る様になっている。私見では、これはエラー処理が面倒に思える(理由は下の「問題点(case1,2共通)」に譲る)。
こうすれば良いという方法は思いつかないが、案としては
例えば "VVV" だと、多くの場合全ての可能性に対応しようとすれば、以下の様に書く必要が出てくると思う
(match-let1 (a b c) (unpack "VVV" :from-string source)
(cond [(eof-object? a) ...]
[(eof-object? b) ...]
[(eof-object? c) ...]
[else ...]))
なぜなら、仮に
(match-let1 (a b c) (unpack "VVV" :from-string source) (fun a b c))
の様に使える関数 fun があったと仮定する。 (この例では (fun a b c) の様に使っているが、引数の組合せや数は何でもいい)
2つ上のプログラム辺の様に、エラーの箇所毎に分岐するなら (unpack "V") を3回やった方が良い気がする。
(port-for-each (match-lambda
[(a b c)
....
])
(cute unpack "VVV" :input port))
の様に reader として使える様になる。 (このケースに限らず port-for-each などのループと #<eof> を組合せるのが一番無駄がないと思う(#<eof> が陽には見えないが)、逆にこれら以外のケースで #<eof> が意味のある記号として働くケースを知らない)
でもこれだと、port から読む場合は便利だが :from-string など1回しかやらない場合は #f の方がいいかもしれない。and, and-let* などと組合せられるので
case2 については、何も考えつかない
Shiro(2011/01/09 23:53:00 PST): とりあえず、データとして#<eof>が返るのは 意図したものというよりは実装上の見過ごしと考えてください。#<eof>は 入力における異常値であって、途中で#<eof>に出会ったら処理全体が#<eof>を返す、 もしくは失敗とすべきです。 (これを簡潔に書くにはmonadが使えるといいんですが、それはまた長くなるので置いときます)。 で、予定よりも入力が短いことを許容するなら、それはtemplate側で「こっから先はオプショナル」 という指定を入れられるべきで、足りない分についてはデフォルト値を指定するなど。 ただ、現在のtemplate文法を拡張してゆくのは無理があるので、 binary.packの位置づけとしては「Perl的コードの手軽なporting」 「使い捨てスクリプト」用とするつもりです。
真面目にバイナリI/Oを行う方法としては、 binary.ioを拡張して構造データを扱えるようにすることを考えています。 既にtrunkには実験的なコードが入ってるのですが、
(define-fstruct header ((version ftype:ulong) (xsize ftype:ulong) (ysize ftype:ulong)) )
というふうに構造体を定義しとけば、
(define h (read-fobject header)) h => #<fstruct header>
というようにバイナリとして読み込んで、
(header-version h) (header-xsize h) (header-ysize h)
などのアクセサでフィールドにアクセスできます。 あるいはu8vectorに格納されたバイナリデータの指定のオフセット位置からを header構造体とみなして各フィールドにアクセスする、など。
これが出来たら、binary.packはその上の層として再実装することになるかなと。 pack指定文字列をfstruct定義へと「コンパイル」する感じ。 今のtrunkの実装はまだ変わると思うのであてにしないで欲しいのですが 方針としてはこんなとこです。
koguro(2008/10/04 03:03:14 PDT): report-error が undocumented なのでそもそも使っていいのか分からないのですが、別スレッドで REPL を実行しているときに report-error でエラーを表示したいときがあります。ところが、スレッド内では VM の defaultEscapeHandler が何もしない処理(thread_error_handler) になってしまっているため、現在の report-error の実装だとエラーが何も表示されないで終わってしまいます。できれば、フラグ指定でもいいのでエラー表示を行うようにしてほしいです。
nekoie(2008/02/08 07:28:47 PST): define-in-moduleは、モジュール名シンボルだけではなくモジュール実体を渡す事も可能で、ドキュメントにもそう書いてあるのですが、special formなので、define-in-module自身の方が引数よりも先に実行されてしまう為、
(define m (make-module #f)) (define-in-module m hoge 123) => *** ERROR: Compile Error: define-in-module: no such module: m
となってしまいます。
(eval `(define-in-module ,m hoge 123) (current-module))
を実行すれば望む結果を得られるのですが、ちょっと分かりにくいので、
(define (bind-in-module env symbol expr) ; 名前は適当 (eval `(define-in-module ,env ,symbol ,expr) (current-module)))
みたいな手続き版も提供してあった方が便利な場合もあると思います。 (とは言え、一行なので、使用頻度を考えると、毎回書いてもいいレベルだとも思いますが)
Shiro(2008/02/08 14:31:26 PST): eval使うなら、
(eval `(define hoge 123) m)
で良いのでは。実行時にグローバルな束縛を追加してゆくのは プログラムの一貫性という観点からはあまり好ましくないので、 わざと不便にしてあります。
nekoie(2008/02/08 16:12:49 PST): 諸事情により、
(define m (make-module #f)) (eval '(extend) m)
のような、defineが存在しない環境に、モジュール外から束縛を与えたかったので、 define-in-moduleを使う必要がありました。 ただ、この状況(define束縛無し)は滅多に無さそうなので、 もし対応するなら、リファレンスのdefine-in-moduleのところに 「evalを使えば可能」という事を追記してもらうぐらいで良さそうです。 (最初に前述のエラーに出会った時に、evalを使う事になかな気付かず、 結構回り道をしてしまったので)
Shiro(2008/02/08 16:39:05 PST): ああ、そういうケースがあるんですね。 extendする前に必要な束縛が決められるなら先に(eval `(define ...)) してから (eval '(extend) m) すればいいわけですが、後から束縛が増えるとなると そうもいきませんか。
evalを使うのは最終手段なので、evalを使うことが自力で思いつける人にしか 使ってほしくないなあ、という思いはあります。
むー、こういう用途を考えるとむしろdefine-in-moduleを拡張すべきかなあ。 設計的に安全なのは、無名モジュールを作った時にフラグによって 「モジュールに束縛を注入する手続き」も同時に得られるようにしといて、 その手続きを使って束縛を入れて行く、ってのはありそうです。 その手続きを手にしていない人には束縛がいじれないと。 でもevalがあったらすり抜けられちゃうから無駄か…
nekoie(2008/02/10 19:49:45 PST): うーん、なるほどです……。 evalがあっても、無名モジュール空間内にdefineがなければ、 (現仕様の)define-in-moduleを使わない限り束縛は追加できないので、 (define-in-moduleを廃止か仕様変更して)無名モジュール作成時に 束縛注入手続きを得られるようにするのでよさそうなんですが、 もし↑の「eval内で、macroやspecial formの実体を、macroやspecial formとして扱ってほしい」パッチを 適用した場合、結局、eval越しにdefineを実行できてしまうので、 ややっこしい事になりそうです。
leque(2007/10/29 17:04:13 PDT): 現在リテラルの正規表現はデフォルトで最適化されますが、これをある程度制御できようになるとうれしいです。というのは、SRE をいじっているときに困ったのを思い出したのですが、正規表現の埋め込みや合成をする場合に、rep → rep-while のように文脈に依存した最適化がされてしまうとそういった操作が難しくなるからです。少し用途は違いますが、Ruby では正規表現内の式展開が一度しか行われないようにする最適化する記法として、/.../o というのがあります(これに倣うと最適化なしは #/.../o0 ?)。
文字列の \u 記法等を R6RS と同様に ; をつけて \u3000; のようにもできると嬉しいです(SXML を書いていたら普通の文字列に紛れてしまったので)。
Rui(2006/11/15 01:23:04 PST): letrec*を提供してほしいです。現状のGaucheのletrecがletrec*の動作になっているので、名前を定義するだけでよいかと。
Rui(2006/10/13 04:56:33 PDT): モジュールをuseしているのに、エクスポートしている束縛を使っていないとき、それを指摘してくれる機能があるとよいです。gauche.testのtest-moduleが警告を出力してくれるとうれしいかも。
2006/10/12 03:17:18 PDT: string interpolation で例えば ,@a 辺りを (tree->string a) に 展開してくれると、短く書けてよいかも。
===================================================================
RCS file: lib/gauche/interpolate.scm,v
retrieving revision 1.1
diff -u -r1.1 lib/gauche/interpolate.scm
--- lib/gauche/interpolate.scm 2006/11/17 03:40:54 1.1
+++ lib/gauche/interpolate.scm 2006/11/18 00:44:11
@@ -40,6 +40,7 @@
(export string-interpolate)
)
(select-module gauche.interpolate)
+(autoload text.tree tree->string)
(define (string-interpolate str)
(if (string? str)
@@ -56,13 +57,18 @@
(cond ((eof-object? c2) (write-char c acc) (accum c2 acc))
((char=? c2 #\,)
(write-char (read-char) acc) (accum (read-char) acc))
- ((char-set-contains? #[\x00-\x20\),\;\[\\\]\{\}\x7f] c2)
+ ((char-set-contains? #[\x00-\x20\)\;\[\\\]\{\}\x7f] c2)
(write-char c acc) (accum (read-char) acc))
+ ((char=? c2 #\@)
+ (read-char)
+ (cons (get-output-string acc)
+ (insert '(with-module gauche.interpolate
+ tree->string))))
(else
- (cons (get-output-string acc) (insert))))))
+ (cons (get-output-string acc) (insert 'x->string))))))
(else
(write-char c acc) (accum (read-char) acc))))
- (define (insert)
+ (define (insert to-string)
(let* ((item
(with-error-handler
(lambda (e)
@@ -70,7 +76,7 @@
(lambda () (read))))
(rest
(accum (read-char) (open-output-string))))
- (cons `(x->string ,item) rest)))
+ (cons `(,to-string ,item) rest)))
(cons 'string-append
(with-input-from-string str
(lambda () (accum (read-char) (open-output-string)))))
jingu(2006/04/28 07:37:02 PDT): getaddrinfoに渡すhintsを<sys-addrinfo>を作らずに、 キーワード引数で渡すことができるものがあると便利だと思うのですが、 いかがでしょうか。
(define (getaddrinfo node service . hints)
(let-keywords* hints ((flags 0)
(family PF_UNSPEC)
(socktype 0)
(protocol 0))
(sys-getaddrinfo node service
(make-sys-addrinfo :flags flags
:family family
:socktype socktype
:protocol protocol))))
Windows環境でwww.cgiを利用してcgiを使おうとすると、cgi-headerの出力が適正でなくて、正常なレスポンスが返ってきません。\nの部分が0d 0aの2バイトを出力してしまっており、結果的に\r\nが0d 0d 0aとして扱われるためのようです。
\r\nを\x0d\x0aと書き換えても結果は同じだったので、出力の段階で何らかの変換をしてるのかと想像してます。\nを出力すると0d 0aになるのは自然だと思いますのでwww.cgi側で何か対策を取れないでしょうか?とりあえずは\r\nを\nだけに書き換えて対処してますが、もし明示的に改行コードを変えれる方法があるのなら適用してもらえれば助かります。
2006/04/28 05:52:21 PDT
genstubのdefine-cclassでオブジェクトを比較する関数を指定できるようになるとうれしいです。
koguro(2006/04/08 18:11:41 PDT): stub用のAPIでlong doubleとScmBignumとを変換するScm_MakeBignumFromLongDoubleとかScm_BignumToLongDoubleがあるとうれしいです(これがあるとc-wrapperでlong double対応ができるので)。
rfc.httpのhttp-get, http-put, http-postが認証に対応してくれるといいですね。401を受けたら、自分で特にハンドルしなくてもAuthorizationヘッダつきのリクエストを再送信してほしいです。
いつもlet-valuesとかを使うときに「あれっ、SRFIの何番だったけ?」と悩んでしまうので、(use srfi)とかするとsrfi-*のモジュールを全部読み込んでくれるとうれしいです。--koguro(2005/11/23 02:43:28 PST)
Nonblockingなconnect(2)をする方法があるとうれしいです。いまはソケットのfdをfcntlでノンブロックにすることはできて、socket-connectを呼ぶことまでできますが、nonblockingな場合はsocket-connectの呼び出しが失敗に終わるので、socket-statusが返すソケットの内部状態が、fdの状態を示したものになりません。(たぶんnonblocking I/Oはひととおり対応予定リストに入っていると思いますけど、一応要望です。)
いくつかの数論的なアルゴリズムを実装するときに、剰余付き累乗が組込みで入っていると割と実用的な速度にできそうなのですが、標準で入らないでしょうか。今すぐ必要というわけでもないので気長に待つ感じで。
アルゴリズムをSchemeで書くとこんな感じ:
; pを法としたaのx乗
(define (pow-mod a x p)
(let ((a (modulo a p))
(n (integer-length x)))
(let loop ((result 1)
(i 0)
(a a))
(if (= i n) result
(if (logbit? i x)
(loop (modulo (* a result) p) (+ i 1)
(modulo (* a a) p))
(loop result (+ i 1)
(modulo (* a a) p)))))))
(define (make-dh g p)
(let ((pri-key (random-integer p)))
(list g p pri-key (pow-mod g pri-key p))))
(define dh-g car)
(define dh-p cadr)
(define dh-pri-key caddr)
(define dh-pub-key cadddr)
(define (dh-make-share-key dh pub-key)
(let ((pri-key (dh-pri-key dh))
(p (dh-p dh)))
(pow-mod pub-key pri-key p)))
ソケットにwrite-blockしたとき、書き込めるだけのバイトを書き込んでブロックしない方法を提供してほしいです。selectとread-block、write-blockを使って、シングルスレッドのサーバで複数のクライアントを同時にサポートしようとしているのですが、ソケットを読まないクライアントがいるとサーバが書き込みでブロックしてしまいそうです。
Shiro(2005/09/05 14:00:18 PDT): 確かに。これは何とかしないとだめですね。 ソケットをnonblockにするのはgauche.fcntlでできると思いますが、 Gauche内部でwrite(2)がEAGAINを返した時の処理が難しい。Schemeレベルでの portへの書き込みからwrite(2)までにいくらでも任意のCレベルの処理が 入る可能性があるので、EAGAINをSchemeレベルで捕捉したとしても write(2)から再開する手段がありません。
Cレベルのport APIを全部トランポリンで書ければcall/ccで復帰できて 綺麗なんですが、Cコードの方がえらく複雑になるので避けたいです。 となると、(1)write-block限定、(2)procedural portやconversion portが 噛んでない、生のfile port限定、という特定の条件下でのみ、EAGAINを port API内で捕まえてwrite-blockが特定の戻り値を返す、みたいな 方法が現実的な線かもしれません。条件がかかるのが醜いですが…
Shiro: Port回りは0.9までに直さなくちゃならない項目の筆頭なので、 たぶん0.8.6後に本格的に取り組むことになると思います (srfi-68の進行も 横目で見てないとならないんですが)。そこで対応を考えたいと思います。
Shiro: これはそう簡単ではないんですよ。=> 議論はGauche:Schemeコードのファイナライザ
export-allする際に、頭が%のものはexportしないようなexport-all*が欲しいです。prefixが設定できればなおいいのですが、%固定で充分だと思います。今作っているモジュールのpublic/private数が62/3なので大変なことになってまして・・・。--hira(2004/03/17 02:35:42 PST)
(define-syntax define-public
(syntax-rules ()
((_ (f . args) . body)
(begin
(define (f . args) . body)
(export f)))
((_ i v)
(begin
(define i v)
(export i)))))
gosh> (define my-path "fobar")
my-path
gosh> (add-load-path my-path)
*** ERROR: string required, but got my-path
Stack Trace:
_______________________________________
0 (%add-load-path path)
At line 30 of "/usr/local/share/gauche/0.6.3/lib/gauche-init.scm"
Shiro: ロードパスはコンパイル時に決定していて欲しいので、add-load-pathはマクロにしてリテラル文字列しか受け付けないようにしています。 add-load-path内で変数を評価するようにしてしまうと、例えば次のフォームはうまく動きません。
(begin (define my-path "foobar")
(add-load-path my-path))
beginフォーム全体がまずコンパイルされ、その後評価時に"foobar"が評価されmy-pathへと束縛されますが、add-load-pathそのものはコンパイル時に処理されなければならないためです。
ただ、コンパイル時に値が確定出来る式をadd-load-pathが取ることを許す、という変更は可能ですね。例えばマクロの束縛はコンパイル時に確定しているので(でないとマクロ展開が出来ない)、こんなふうに書けるようにはできるかもしれません。
(define-macro (my-path) "foobar") (add-load-path (my-path))
ちょっと考えてみます。
現在の仕様でロードパスを実行時に変更するのは、変数*load-path*を直接変更することで可能です。
(push! *load-path* "foobar")
マニュアルでは*load-path*を直接いじるのは非推奨としていますが、それは上記のような評価のタイミングによる混乱を避けるためで、分かって使うぶんには問題ありません。 (2002/09/28 18:10:11 PDT)
skimu: ご丁寧な解説ありがとうございます。 コンパイル時に決まってなきゃいけないのは autoload をきちんと処理するためですよね? 一応確認。こういうブートストラップ的な問題は考えるとすぐ頭痛くなっちゃいます ^^; しかし add-load-path を使わない方向で検討したら却ってしっくりくるものに仕上がりました。ちなみに何をやっていたかというと todoさんのページにあった Gauche-gl のかっこいいデモを MacOSX のアプリケーションバンドルにして遊んでいたのでした。2002/09/28 21:36:32 PDT