Gauche:WishList
- 安全性について
- Portableなパターンマッチング
- util.matchで非線形パターンに対応してほしい
- rfc.http オプションヘッダの扱い
- モジュール拡張子を追加するオプション
- MinGWでc-wrapperを使いたい
- object-applyに登録したメソッドを削除したい
- Windowsのコマンドプロンプトで日本語(CP932)の表示と入力
- uri-encode の大文字、小文字
- <sockaddr> を equal? できる様にして欲しい
- unpack で template に叶う入力でない場合の戻り値の変更
- 別スレッドで report-error を呼んだ場合でもエラーを表示できるようにしてほしい
- define-in-moduleの手続き版が欲しい
- 正規表現の最適化を制御したい
- 文字列の \x, \u, \U 記法
- letrec*
- useしているのに使っていないモジュールを指摘する機能
- tree->string and string interpolation
- getaddrinfo
- cgi-headerでの改行(Windows環境)
- define-cclassにcomparatorを
- long doubleとScmBignumの変換
- http-getの認証対応
- srfi-*を全部読み込むモジュール
- Nonblocking Connect
- 剰余付き累乗
- Nonblocking Write
- any, every for gauche.collection
- after-gc-hook
- weak-hash-table
- export-all*
- add-load-path
- 対応済み: Gauche:WishList:done
- 保留・代案 : Gauche:WishList:pending
安全性について
- hamayama(2024/06/17 09:54:52 UTC): 安全性について、気になっている点があります。
- (1) `-V` オプションの出力
出力結果にディレクトリ構成やユーザID等が含まれている場合がありえる。
(例えば、Windows 用バイナリの build.configure 等)
→ srfi-176 version-alist ?
- Shiro:なるほど。-V の出力をエラー報告とかに貼り付ける時は気になりますね。何らかの環境変数でフィルタできるようにしておけばいいかな。https://github.com/shirok/Gauche/issues/1042 でトラックします。
- (2) compile-r7rs が、環境変数 COMPILE_R7RS を設定すると、任意のプログラムを実行できてしまう。
(今のところ、Windows では、 sys-unsetenv でエラーになるので実行できない。
ただ、file-is-executable? の実行ファイルチェックは、Windows ではファイルが読めれば何でも #t になる)
→ srfi-138 ?
- Shiro: これはもうちょっとどういう文脈で危険になり得るかを詰めたいです。昔の感覚では、攻撃者が環境変数を設定できる状況では、Gaucheそのものが改変されている可能性も同等にあるのでそこ気にしても意味が無い、というものですが、アプリのインストール権限が制限されてる環境とかでは問題になり得るのかな。もしこれがまずいとすると、`EDITOR`とか`PAGER`など環境変数経由で外部プログラムを呼び出す口がいくつかあるのでまとめて対策する必要があります。
- hamayama(2024/06/17 22:30:11 UTC): 私がこのプルリクエストを確認して思ったのは、
COMPILE_R7RS の仕様がヘルプに表示されず、何の確認もなく実行されるので、心の隙をつけそうだなということでした。
(数年も経てば、皆が仕様を忘れていそう)
また、コンパイルにはビルドスクリプトを作成することがよくあるので、自然な感じでプロジェクトに入れられそうということと、
通常は処理系がインストールされていて実行が不要なので、実行のタイミングも不定にできると思いました。
- hamayama(2024/06/17 22:30:11 UTC): なので、その状況であればそもそも何でもできるだろうというのは、その通りです。
(コミットを見ても見つかりにくいようにはできそう、という感じです)
- Shiro(2024/06/18 10:55:50 UTC): 私としては、
COMPILE_R7RS
は処理系に関わらず「そういうもの」なのでセキュリティ的な穴とはあまり感じられないんですが、(1)うっかり試験的に設定していたのを忘れて、Gaucheのcompile-r7rs
を起動してるつもりがそうなってなくてトラブルシューティングに悩む、というのと(2)suidプログラムで実行してたら確かに穴になる、という点はあると思います。前者については「違うプログラムを実行するよ」というメッセージがあると親切ですし、後者についてはsuid実行時に禁止するのはありと思います。
- hamayama(2024/06/19 02:45:27 UTC): 一応、考えられるシナリオをまとめておきます。
(1) プロジェクトの管理者が COMPILE_R7RS の仕様を知らない。
(2) コンパイルすると独立して実行できますよというプルリクエストが来る。
;; setting and compile
export COMPILE_R7RS=wrong-something
compile-r7rs -o project.exe project.scm
(3) マージされ、好奇心のある人や Gauche の入っていない PC でも実行したい人が起動して感染する。
<参考>
・XZ Utilsの脆弱性
- hamayama(2024/06/19 02:45:27 UTC): まあ、(仕様を確認しないで) どろぼうを招き入れれば、
どんなセキュリティ対策も意味はないということかもしれませんが…
- hamayama(2024/06/19 02:45:27 UTC): あと、別な観点としては、
なぜ Gauche の本体に compile-r7rs が必要なのかという疑問があります。
いろいろな処理系でビルドしたいという目的であれば、別のリポジトリでやれば良いと思う。
(他の実装のコンパイルエラーを問合せされても困るし…)
他の実装を見ても、
・Larceny の compile-larceny
・STklos の stklos-compile
・STklos の srfi-138 対応の要望
のように、個別のコンパイルコマンドは用意していても、compile-r7rs は提供していないし、COMPILE_R7RS にも対応していない。
- Shiro: そのシナリオの「プロジェクトの管理者」は何らかのR7RS Schemeプロジェクトの管理者ですか? Gauche特有のプロジェクトにそのプルリクは来ないですよね。
compile-r7rs
はユーザがconfigure
でオプション指定しないとインストールされないですし。
まあでも、同名のコマンドの別実装へのディスパッチを環境変数でやるってのはちょっとobscureではあります。Debianのalternativeの仕組みのようにシステム側で切りかえるなり、PATH
によりマネージするなりした方が何をやってるか明確ではある。
- hamayama(2024/06/21 12:28:40 UTC): 確認したのですが、確かに compile-r7rs は入らないようですが、
リンク元の gauche-compile-r7rs およびライブラリの lib/tools/compile-r7rs は入っているし、
gauche-compile-r7rs を実行すると Usage: compile-r7rs と出るし、
COMPILE_R7RS を設定するとそっちが実行されるし、
R7RS でない普通の Gauche のプログラムもコンパイルできてしまうのですが (すごい技術やが…) 。
これは、実質 compile-r7rs の機能を提供しているのでは?
- Shiro: そうです。でもそれを使う人は敢えて
gauche-compile-r7rs
を機動するんですから、わかっててやる人ですよね。今考慮すべきは一般のR7RSユーザでは。 結構複雑な問題なので、 https://github.com/shirok/Gauche/issues/1043 でトラックします。とりあえず、「一時的にCOMPILE_R7RS
を設定したのを忘れててハマる」というパターン防止のためにwarningは出すようにしました。
- hamayama(2024/06/22 21:47:08 UTC): 本件は、SRFI-138 の COMPILE_R7RS の機能を未サポートとすることで対策されました。
( コミット e97e5d8 (2024-6-22) )
- どちらも仕様通りであるとは思うのですが、情報漏洩や意図しない実行のリスクを減らしてほしい。
- あと、できれば、リポジトリの Security タブで「Private vulnerability reporting」を Enable にしてほしい。
(負担が増えるかもしれないので、判断はおまかせします)
- Shiro: 対応しました。
- あと、プルリクエスト、SRFI、スポンサー等から、例えばバックドアにつながるような提案がないか、常に気を付けてほしい。
(滅多にないとは思いますが…)
Portableなパターンマッチング
srfi 241 がPortableなPattern matchingのようですが実装される可能性ありますでしょうか。 初心者なんですが、できるだけPortableなコードを心がけていて、srfi 241を知りました。
- 齊藤 (2023/10/16 14:14:15 UTC): SRFI はどの処理系にも実装されるべきという性質のものではありません。
あくまでも議論の場に過ぎず、その成果を採用するもしないも処理系 (またはライブラリ) の実装者の判断次第です。
(言語仕様の改定にあたって過去の SRFI をほとんどそのまま採用したり、改定の検討項目を SRFI 上で議論することはあります。)
なのでポータブルであることが目的であるなら SRFI はそれほどあてになりません。
参照実装が用意されている SRFI はそれを適当にコピペすれば動く場合もあるんですが、 SRFI 241 についていえばこの参照実装は R6RS を前提にしているので Gauche に移植するのは面倒そうに見えますね。 - お返事ありがとうございます。新しいSRFIはR7RSを意図して提案されているのかと思ったのですが、そう単純でもないようですね。ありがとうございます。パターンマッチングは頻用しそうなので、できるだけ普遍的な知識として習得したいなぁと思ったのですが、util.match で始めるがよいのですかね。
- 齊藤(2023/10/18 01:02:48 UTC) : R7RS を前提としてポータビリティを意識するなら
Alex Shinn 氏のパターンマッチライブラリは良い選択肢になりえるかもしれません。
R7RS で実装されていてライセンス上の制限もないので処理系が採用していなくても必要であれば自分のプロジェクトに含めてしまえば (R7RS 準拠の処理系では) いつでも使えます。
あるいは、パターンマッチライブラリはパターンの表現からパターンを辿るコードを生成するマクロに過ぎませんから自分にとって必要な程度の簡易的なものを書いてみるというのも面白いでしょう。 - ありがとうございます。調べてみるとAlex Shinn氏はChibi Schemeの作者でもあるようですね。Gaucheの機能使いつつ、いつかは自分で使いたい機能を作れるようになりたいなぁと思います。
util.matchで非線形パターンに対応してほしい
はじめて書き込みします。よろしくお願いします。 現在はパターン内に同じ変数を書くとエラーとなりますが、 これを同じ変数のところは同じ値の場合にマッチするようにしてほしいです。
動作イメージ
gosh> (match '(1 1 1) ((x x x) "same") (_ "different")) "same" gosh> (match '(1 1 2) ((x x x) "same") (_ "different")) "different"
対応している他言語の例
- Pure
In contrast to Haskell, patterns may contain repeated variables (other than the anonymous variable), i.e., they may be non-linear.
https://agraef.github.io/pure-docs/pure.html#non-linear-patterns-and-syntactic-equality
- Egison
Egison では1つのパターン内で同じ変数が複数現れるパターンを記述することができます。
- Erlang,Prolog
- Schemeライブラリ
MatchComp is Christian Queinnec's pattern-match compiler code for compiling non-linear, second-order patterns on S-Expressions.
https://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/code/match/matchcmp/0.html
そこで0.9.10_pre1のutil.matchでの変更案の最低限のたたき台を書いてみました。
--- old/libsrc/util/match.scm 2020-07-30 20:16:34.911257510 +0900 +++ new/libsrc/util/match.scm 2020-07-31 23:32:13.146314742 +0900 @@ -20,6 +20,7 @@ match:every match:error)) (select-module util.match) +(define non-linear #t) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Pattern Matching Syntactic Extensions for Scheme @@ -455,9 +456,10 @@ (define (bound p a k) (cond ((eq? '_ p) (k p a)) + ((and (identifier? p) (memq p a)) + (if non-linear (k p a) + (match:syntax-err pattern "duplicate variable in pattern"))) ((identifier? p) - (when (memq p a) - (match:syntax-err pattern "duplicate variable in pattern")) (k p (cons p a))) ((and (pair? p) (equal? 'quote (car p))) (k p a)) @@ -645,6 +647,8 @@ See the ``Keyword and symbol integration'' section \ of the manual for the details.\n" p x) (emit `(equal? ,e ,p) sf kf ks)) + ((and non-linear (identifier? p) (assq p v)) + (emit `(equal? ,e ,(cdr (assq p v))) sf kf ks)) ((identifier? p) (set! v (cons (cons p e) v)) (ks sf)) ((null? p) (emit `(null? ,e) sf kf ks))
マクロの展開結果で、(equal? (cadr e) (car e))と(equal? (caddr e) (car e))の処理が入っていることが確認できます。
gosh> (macroexpand '(match e ((x x x) x))) (let ((#:G94 (lambda.0 (x) x))) (if (and (pair? e) (pair? (cdr e)) (equal? (cadr e) (car e)) (pair? (cddr e)) (equal? (caddr e) (car e)) (null? (cdddr e))) (#:G94 (car e)) (match:error e)))
エラーとしていた場合の挙動を変更するものであり、これまで動いていたコードに対する影響はないと思います。 が、念のため、変数non-linearを#fにすると従来のエラーとする挙動に戻るようにしてあります。 ご検討よろしくお願いします。
- Shiro(2020/08/01 07:12:10 UTC): 現在、SRFI:204にてWrightの
match
(Gaucheがベースにしているもの)をAlex Shinnがsyntax-rulesで書き直したものが議論されています。 そちらでは同一変数への束縛がサポートされているので、 このsrfiがfinalizeされたら合わせてサポートします。 実装はsrfi-204の参照実装を持ってくるか、er-macroで書き直すかも。 Wrightの元ソースは自分自身で展開されたコードを含んでいて手がつけにくいので。
- k(2020/08/01 09:44:40 UTC): srfiになるならそれがベストですね。srfi-204が使えるようになるのを楽しみに待ちます。それにしてもsrfi-204がDraft #1 published: 2020-07-15とはなんというタイミングの良さ。
rfc.http オプションヘッダの扱い
kobapan?2017/12/24 19:44:21 UTC
(http-get "localhost:8012" "/" :Authorization #f)
としたときに送信されるヘッダが、
host: localhost:8012 user-agent: gauche.http/0.9.5 authorization: #f
となるのにとまどいます。
host: localhost:8012 user-agent: gauche.http/0.9.5
となって欲しい。
- Shiro(2017/12/24 22:38:36 UTC): 尤もです。fixをコミットしました。 https://github.com/shirok/Gauche/commit/bd1bcb9a0949038b9cd7fd661fa211b1a9cecd4a
モジュール拡張子を追加するオプション
Kei(2015/01/19 20:26:09 UTC): Chibiが.sldをR7RSのライブラリに採用したので、それがデファクトになりつつあるのですが、Gaucheには簡単に拡張子を追加するオプションがなくて毎回不便です。
$ gosh -r7 -e '(set! *load-suffixes* (cons ".sld" *load-suffixes*))'
と毎回打ってもいいのですが、オプション一発で追加(prependの方が使いでがありそう)できると嬉しいです。
- Shiro(2015/01/19 21:25:21 UTC): それはそれで便利そうですが、sldについてはHEADでは既に認識するようになっています。
MinGWでc-wrapperを使いたい
h(2014/09/07 14:07:57 UTC):Gauche 用 の c-wrapper を MinGW (32bit) 上で動くように改造してみました。
https://github.com/Hamayama/c-wrapper-mg
libffi-3.1がMinGWに対応しているようだったので、試行錯誤の末どうにか動かすことができました。
ただ、libffi-3.1そのままではだめで、修正が必要でした。
あと、Gaucheでちょっとしたプログラムを作ったときに、実体はGitHub等に置くとして、
こういうのを作ってみましたと報告できるような、「Gauche:作品集」みたいなページを
このWikiに作ってもよいでしょうか。
- Shiro(2014/09/07 20:10:19 UTC): Gauche:Packagesに載せるほどにはまとまってない、 ということですか?
- h(2014/09/07 21:40:19 UTC):そうです。実験的なものとか、デモプログラムとか、簡単なゲームとか、
何かのアルゴリズムをGaucheで計算してみたとか、そういうものをこのWishListのように
新しいものを一番上に追加していけるページがあるとよいかなと思いました。 - Shiro(2014/09/08 07:51:14 UTC): Gaucheのページの「スクリプトの例」にずらっと 個別ページへのリンクがあるので、Gauche:なんとか、というトピックのページを作って 「スクリプトの例」に足してもらったら良いかと思います。増えすぎたらまた整理すればいいですし。 トピックのページは、他の人が別解を足す可能性とかを考えて、あまり属人的にせず 「Gaucheでこういうのを書きたい時はどうよ?自分はこう書いてみた」的な展開にしといてもらえると 良いかと。もちろんトピックページに直接コードを置かずgithub等へリンクするだけでokです。
- h(2014/09/08 12:01:00 UTC):回答ありがとうございます。Gaucheのトップのところによい感じにまとまっていたのですね!
トピックのページを作ってGaucheページからリンクする形でやってみます。
- h(2014/09/09 20:04:34 UTC):このWikiのGaucheのページですが、本体のドキュメントページ
http://practical-scheme.net/gauche/memo-j.html
から、関連ドキュメントとしてリンクしてはどうでしょうか。
あと、別件ですが、
http://practical-scheme.net/gauche/packages-j.html
のページの「Gauche Garbage Collection」のURLがリンク切れのようです。現在は、
http://sourceforge.net/projects/gauchegc/
の方に引き継がれているようです。
object-applyに登録したメソッドを削除したい
h(2014/08/26 11:20:48 UTC):一時的にobject-applyにメソッドを追加して、作業後に元に戻すことは可能でしょうか。
例えば、以下のようなケースです。
(define-method object-apply ((x <top>) . args) (cons x args)) ;; (リストの先頭が手続きでなくてもよい世界) (print (1 2 3 4 5)) (print (apply + (1 2 3 4 5))) ;; (以後は元の世界に戻したいのだけど。。。) (?????)
- Shiro(2014/08/26 12:13:18 UTC): 今は直接の手段はないですね。グローバルな効果を持つうえに
戻せない、という現在の仕様は気持ち悪くはあるのですが。
応急処置的に対応するなら、総称関数のmethodsスロットを直接書き換えてしまうという
手はあります。但しスレッドセーフでないうえ、今後ずっと動き続ける保証はありません
(メソッドキャッシュなどが導入された場合にうまくいかなくなるかも)。
最終的には影響範囲を限定できる仕組みを導入するのが良いと思うのですが。
h(2014/08/26 20:42:50 UTC):methodsスロット使って以下のようにしてみました。一応戻せたようですが。。。
;; object-applyのメソッドを保存 (define mold (slot-ref object-apply 'methods)) ;(print mold) ;; object-applyにメソッドを追加 (define-method object-apply ((x <top>) . args) (cons x args)) ;; ***** リストの先頭が手続きでなくてもよい世界 ***** (print (1 2 3 4 5)) (print (apply + (1 2 3 4 5))) ;; ***** 元の世界に戻す ***** ;; object-applyのメソッドを復帰 (define mnow (slot-ref object-apply 'methods)) ;(print mnow) (for-each (lambda (m) (delete-method! object-apply m)) mnow) (for-each (lambda (m) (add-method! object-apply m)) (reverse mold))
- Shiro(2014/08/26 20:51:29 UTC): あ、delete-method!があったの忘れてました。 それ使えばスレッドセーフです。また、全部を保存しておいて戻さないでも、 取り除きたいメソッドだけ選んでdelete-method!すれば安全なはず。
h(2014/08/27 07:19:49 UTC):ありがとうございます。メソッドを取り出してdで表示してみると、
required, optional, specializers というスロットがあったので、これらチェックしてやってみます。
ひとつ気になったのが、
(define-method object-apply ((x <top>) . args) (cons x args))
を、
(define-method object-apply ((x <top>)) x)
と変更しても、specializers の値が同じ (<top>) になったことです。
ユーザリファレンスの define-method の説明によると、
前者は (<top> . <top>) になりそうな感じでした。
ただ、optional は、前者が #t で後者が #f なので、区別は可能です。
そして、両方実行するとちゃんと別々のメソッドとして登録されました。
h(2014/08/28 20:30:20 UTC):一応できたものが以下になります。
https://github.com/Hamayama/noqlist
(実験用という位置づけです)
- Shiro(2014/08/28 20:44:19 UTC): rest引数はspecializersとは別扱いです。 そもそも、例えば (<top> . <integer>)等のような形で引数が渡ってくることはありえないわけで、 rest引数の型は見る意味がないからです。
h(2014/08/30 03:57:51 UTC):同様の方法で「Gauche:数式の中置記法」を参考に中置記法をモジュールにしてみました。
https://github.com/Hamayama/numinfix
rest引数の件は了解しましたが、ユーザリファレンスの「7.4 ジェネリックファンクションとメソッド」の
define-method のところで specializers: (<myclas> <top> . <top>) という例がのっており、
specializers のみでメソッドを特定できるように読めます。
多分この記述の specializers と、メソッドのスロットの specializers が別ものなのかとは思いますが、はまりそうではありました。
- Shiro(2014/08/30 15:32:27 UTC):なるほどたしかに紛らわしいですね。ドキュメントを直しておきます。
Windowsのコマンドプロンプトで日本語(CP932)の表示と入力
h(2014/06/04 14:40:02 UTC):Windows 8でもコマンドプロンプトはCP932がデフォルトのようです。
それで、こちらのページに文字コードを変換しながら入出力するサンプルが載っていました。
http://saito.hatenablog.jp/entry/2014/04/14/104006
リダイレクトがエラーになるので判定を追加してモジュールにしてみました。
https://github.com/Hamayama/msjis
(ただし、まれにキー入力を受け付けなくなることがあります。。。)
以前からある要望だと思うので、ひとつの方法ということで挙げておきます。
uri-encode の大文字、小文字
ryoakg(2013/08/22 12:29:35 UTC):
要望なのか何なのか分からない話で、もうしわけないですが、
uri-encode でエンコードされる結果を、大文字に固定するか、選べる様にした方がいいのかな? という話です。
状況としては、
https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?rest-signature.html
のリクエストを作っていました。
その中で uri-encode を使ったのですが、
最初うまくいかなくて
結果として uri-encode の中で使われていた
format の x を X に変えるとうまくいきました。
Gauche のバージョンは 0.9.3.3 です。
あまりwebプログラミングしないので、こういう事がよくあるのか分からないのですが。
以下の様にググってみると
https://www.google.co.jp/search?q=uri+OR+url+%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89+%E5%A4%A7%E6%96%87%E5%AD%97+%E5%B0%8F%E6%96%87%E5%AD%97&ie=utf-8&oe=utf-8&hl=ja
どっちでも良いけど、大文字の方がいいみたいな感じですね。
また、http://dev.worksap.co.jp/Members/t_tanaka/2011/03/30/dotnet-java-urlencode/
に RFC3986 の話が引用してありました。
なので、多分長期的には、大文字に固定するか、
大文字をデフォルトにするかにした方がいいのだと思います。
(小文字の方が良い場面は分からないですが)
ただそうすると uri-encode の全ての出力に影響するので、
突然切替えるのも心配な気もします。
一応、プログラム全体は以下です。
amazonに登録して、idもらわないと動かせないので、
すぐ試せなくて面倒な感じなのですが。
(use gauche.experimental.app) (use gauche.experimental.lamb) (use srfi-13 :only (string= string<)) (use rfc.http) (use rfc.hmac :only (hmac-digest-string)) (use rfc.sha :only (<sha256>)) (use rfc.base64 :only (base64-encode-string)) (require "rfc/uri") (with-module rfc.uri (define (uri-encode :key ((:noescape echars) *rfc3986-unreserved-char-set*)) (let loop ((b (read-byte))) (unless (eof-object? b) (if (and (< b #x80) (char-set-contains? echars (integer->char b))) (write-byte b) (format #t "%~2,'0X" b)) (loop (read-byte))))) ) ;;; 以下3つは、事前にアカウント登録が必要 ;;; https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?CHAP_GettingSetUp.html (define *AWS-access-key-id* "") (define *secret-key* "") (define *associate-tag* "") (define *AWS-server* "webservices.amazon.co.jp") (define *API-version* "2011-08-01") ;;; とりあえず全部固定で (define (make-param-list keyword) (define fixed-param-list `(;; fixed ("AWSAccessKeyId" ,*AWS-access-key-id*) ("Service" "AWSECommerceService") ("Version" ,*API-version*) ("AssociateTag" ,*associate-tag*) ("Timestamp" ,($ sys-strftime "%FT%TZ" $ sys-gmtime $ sys-time)) ;; function: https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?CHAP_OperationListAlphabetical.html ("Operation" "ItemSearch") ;; return values: https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?CHAP_ResponseGroupsList.html ("ResponseGroup" "ItemAttributes") ;; arguments: https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?CHAP_OperationListAlphabetical.html ("SearchIndex" "Books") ("Keywords" "computer") )) fixed-param-list) (define (make-sigature params) ($ base64-encode-string $ (cut hmac-digest-string <> :key *secret-key* :hasher <sha256>) $ string-join `("GET" ,*AWS-server* "/onca/xml" ,(http-compose-query #f params)) "\n")) (define (make-uri) (let1 params ($ (cut sort <> (^(a b) (string< (car a) (car b)))) $ make-param-list "dummy") (http-compose-query "/onca/xml" `(,@params ("Signature" ,(make-sigature params)))))) ;;; $ firefox `THIS.scm` ;; (print #`"http://,|*AWS-server*|,(make-uri)") (receive (status headers body) ($ http-get *AWS-server* $ make-uri) (unless (string= status "200") (print status) ;; (exit 1) ) (print body))
大文字と小文字を切替えられる様にする場合の話ですが、
上のプログラムでは直接 uri-encode 使っていなくて、
http-compose-query の中で使っているので、
単純に uri-encode にオプショナル引数を
付ければ良いとならないのが面倒そうです。
選択子としては、
- http-compose-query, http-get などは、単なる便利機能なのであきらめる
- uri-encode に依存する関数、全部にオプショナル変数をつける。面倒。
- gauche.parameter。安易に使っていいか分からないですが。
なのかと思いました。
- Shiro(2013/08/23 02:28:40 UTC): RFCでSHOULDになってるので従うことにしました (大文字を使うように変更)。受け入れる方は大文字でも小文字でも使えるように作ってある「はず」なので、 大きな影響は出ないかと。(uri-encodeした後でハッシュ値を求める、とかやってるプログラムは 壊れるけど、それはuri-encodeを使ってたのが間違い。)
- ryoakg(2013/08/23 05:26:43 UTC): そうですね。uri-encodeした後でハッシュ値を求めたりの部分の方が問題ですね。 動くプログラムとの出力結果の差だけ見てやってたので、全々考えてなかったです^^
<sockaddr> を equal? できる様にして欲しい
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 などするときの全順序な場合とそうでない場合?)
- Shiro(2011/06/26 17:41:56 PDT):
object-equal?
メソッドでできないかな、 とやってみたらできませんね。compareが入ってないとobject-equal?も呼ばれないのか。 object-equal? を呼ぶようにしてしまうという手がひとつありますが、 この問題に関してはハッシュテーブルで比較関数とハッシュ関数をカスタマイズできるように する、という方が根本的な解決になりそうだと思います。 (object-equal? のカスタマイズはグローバルな効果を持つので、 本来はクラスを提供する人が同時に提供すべきで、ユーザが後付けで定義するものではない。) - Shiro(2011/07/26 01:35:42 PDT): equal? が動くに越したことはないので、socket address についてはequal?で比較できるようにしときました。
unpack で template に叶う入力でない場合の戻り値の変更
ryoakg2011/01/09 20:40:46 PST 言いたい事が2点ありますが、分けて書いても、混ぜて書いても、うまく書けそうにないですが、とりあえず混ぜて書きます。
case1 入力を読んでも #<eof> になっている場合
現状(rev7345)
gosh> (unpack "VVV" :input (open-input-string "")) (#<eof> #<eof> #<eof>)
の様に入力が半端な部分だけに #<eof> が入る様になっている。これを #<eof> だけを返す様にして欲しい(リストに入れない)。
case2 入力が半端な場合
gosh> (unpack "VVV" :from-string "aaaabbbbcc") (1633771873 1650614882 #<eof>)
の様に入力が半端な部分だけに #<eof> が入る様になっている。私見では、これはエラー処理が面倒に思える(理由は下の「問題点(case1,2共通)」に譲る)。
こうすれば良いという方法は思いつかないが、案としては
- #f を返す
- (values #f (unpack-skip "VVV" :from-string "aaaabbbbcc")) を返す
- 例外 などが思いついたが、特に根拠はない(後者は無駄に文字列コピーしてしまうのかも)。
問題点(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) の様に使っているが、引数の組合せや数は何でもいい)
- #<eof> を引数として期待している、標準のライブラリ関数はほとんどない(と思う)
- 従って、fun はユーザが書いた関数で、結局その中で eof-object? を使った分岐があるハズ
- これは結局、2つ上のコード辺の condなどの分岐が、どこにあるか? という問題に過ぎなく、特に何も解決していない(と思う)。
2つ上のプログラム辺の様に、エラーの箇所毎に分岐するなら (unpack "V") を3回やった方が良い気がする。
case1 についてのメリット
(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 については、何も考えつかない
問題設定について
- 結局、正規表現に過度な期待をしてしまうのと同じ問題ではないかとも思える。根本的には、この template 文字列が言語としての機能が低すぎるから仕方ない?
- もしそうであるなら、どこまで期待をすべき?
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の実装はまだ変わると思うのであてにしないで欲しいのですが 方針としてはこんなとこです。
別スレッドで report-error を呼んだ場合でもエラーを表示できるようにしてほしい
koguro(2008/10/04 03:03:14 PDT): report-error が undocumented なのでそもそも使っていいのか分からないのですが、別スレッドで REPL を実行しているときに report-error でエラーを表示したいときがあります。ところが、スレッド内では VM の defaultEscapeHandler が何もしない処理(thread_error_handler) になってしまっているため、現在の report-error の実装だとエラーが何も表示されないで終わってしまいます。できれば、フラグ指定でもいいのでエラー表示を行うようにしてほしいです。
- Shiro(2008/10/04 04:15:21 PDT): むむむ。defaultEscapeHandlerとreport-errorの使い方を
自分で書いてて混乱してるようです。defaultEscapeHandlerが設定されている
場合にreport-errorがそっちに制御を渡してるのは、多分defaultEscapeHandlerが
最終的なエラーハンドリングの振る舞いを決定できるようにするっていう意図だった
んだと思うんですが、一方でthread.cでsrfi-18のセマンティクスを満たすために
defaultEscapeHandlerを上書きした時はreport-errorとの干渉を
考えていなかったような気がします。
thread.cはdefaultEscapeHandlerを使うんではなく、thread_entryの部分で デフォルトのguardを噛ませるようにすればいいんじゃないかな。ちょっと考えてみます。
define-in-moduleの手続き版が欲しい
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 ?)。
- Shiro(2007/10/29 17:43:11 PDT): ふーむ。埋め込みや合成をするのは最適化ステージの 前に全部済ませるってのを想定していたんですが、#/.../をリーダーが読みこんでから その中身をいじりたいというような話でしょうか?
- leque(2007/10/29 19:06:54 PDT): そういう感じです。例えば SRE だと (rx (or ,#/ab+c/ "abd")) のようにしてリーダーの読んだ正規表現を埋め込むことができるので、(#/(ab+c|abd)/ "abd") はマッチするのに対して、((rx (or ,#/ab+c/ "abd")) "abd") は #f になるということが起こってしまいます。
- Shiro(2007/10/29 19:15:05 PDT): それならむしろ、最適化前の表現を取り出せるようにして 使ってもらう方がいいかな? ユーザからするとそこでなぜ最適化を 抑制しなくちゃならないかってわかりずらいと思うし、埋め込んだ後で最適化を かけるならコンパイルされた最終状態じゃなくて途中のASTが得られる方が嬉しいですよね。
- leque(2007/11/05 19:36:55 PST): (すばやいレスに気がつかなかった :-)言われて見るとそうですね。ユーザにそこまで判断させるのは逆に煩雑な気がしてきました。
文字列の \x, \u, \U 記法
文字列の \u 記法等を R6RS と同様に ; をつけて \u3000; のようにもできると嬉しいです(SXML を書いていたら普通の文字列に紛れてしまったので)。
- Shiro(2007/10/07 23:40:41 PDT): 仕様的にはデリミタがはっきりしているR6RSの方が良いと思うので いずれ移行するつもりですが、既存の文法と両立できないので、なんらかのフラグを設ける ことになると思います。
- なるほど、互換性の問題がありましたね。了解しました。(2007/10/21 14:28:08 PDT)
letrec*
Rui(2006/11/15 01:23:04 PST): letrec*を提供してほしいです。現状のGaucheのletrecがletrec*の動作になっているので、名前を定義するだけでよいかと。
- Shiro(2007/10/06 01:15:22 PDT): R6RSも決まったんでそろそろなんとかしたいですが、 現在のletrecは最適化がかかったときにletrec*の動作にならない場合があったような 感じが頭の隅に引っかかってるんです。本当にそうなのかどうなのかはcompile.scmを 読み直さないとならないんで保留になってます。
useしているのに使っていないモジュールを指摘する機能
Rui(2006/10/13 04:56:33 PDT): モジュールをuseしているのに、エクスポートしている束縛を使っていないとき、それを指摘してくれる機能があるとよいです。gauche.testのtest-moduleが警告を出力してくれるとうれしいかも。
- Shiro(2006/10/13 06:43:20 PDT): いいですね。確かにプログラムをいじってると(use ...)がたくさん たまって来て、それをリファクタリングした時なんかに整理しやすい何かが欲しいと 思っていました。ランタイムのチェックはオーバヘッドがあるので、テスト時の チェックが良さそうです。
tree->string and string interpolation
2006/10/12 03:17:18 PDT: string interpolation で例えば ,@a 辺りを (tree->string a) に 展開してくれると、短く書けてよいかも。
- Shiro(2006/10/12 03:25:59 PDT): お、それは面白いかも。
- enami(2006/11/17 16:51:35 PST): 一応 with-module 版を貼っておきます。
c.f. http://www.lingr.com/room/gbq0WCLQEF2/archives/2006/11/16
=================================================================== 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)))))
getaddrinfo
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))))
cgi-headerでの改行(Windows環境)
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
- Shiro(2006/04/28 06:23:44 PDT): 手元で試したところ、cygwinだと正常ですが mingwだとstdoutに対する出力で \n -> \r\n の変換がかかってしまうようです。 (cygwinでは選べたような気もしますが)。 stdoutがO_TEXTでopenされてるってことだと思うので、初期化時点で _setmode(fileno(stdout), O_BINARY) とかしてやれば良さげですが、 全部binary modeにしちゃうと困る場合も出てきそうな気もします。どうしよ。
define-cclassにcomparatorを
genstubのdefine-cclassでオブジェクトを比較する関数を指定できるようになるとうれしいです。
long doubleとScmBignumの変換
koguro(2006/04/08 18:11:41 PDT): stub用のAPIでlong doubleとScmBignumとを変換するScm_MakeBignumFromLongDoubleとかScm_BignumToLongDoubleがあるとうれしいです(これがあるとc-wrapperでlong double対応ができるので)。
http-getの認証対応
rfc.httpのhttp-get, http-put, http-postが認証に対応してくれるといいですね。401を受けたら、自分で特にハンドルしなくてもAuthorizationヘッダつきのリクエストを再送信してほしいです。
srfi-*を全部読み込むモジュール
いつもlet-valuesとかを使うときに「あれっ、SRFIの何番だったけ?」と悩んでしまうので、(use srfi)とかするとsrfi-*のモジュールを全部読み込んでくれるとうれしいです。--koguro(2005/11/23 02:43:28 PST)
- Shiro(2006/01/27 20:09:34 PST): 少々大きなアプリになると(use ...) がずらりと 並ぶので、このへんは何とかしたいところではあります。 ただ、srfiにはGaucheの組み込み関数を置き換えるものもあるので、 srfi-*で全部読んでしまうと危なくありませんかね。
- koguro(2006/02/04 16:55:12 PST): おっしゃるとおりformatなんかの挙動が勝手に変わってしまうと混乱の元になりかねないですね。私自身要望が整理できていないのでもともと思っていたことを書かせていただくと、ある機能を使いたいときに明示的にモジュールを読み込む必要があるのか、それとも組み込みで持っている機能なのかをマニュアルを読まずに判断するための基準がちょっと分かりにくいということを感じていました。例えばsrfiで定義されているものはすべて(use srfi-*)と書かなくてはならないというのであればかえって分かりやすい(覚えなくてはならないのが明確であるため)のですが、現状ではsrfiの中でも一部の機能はコアに含まれていたりするので、ちょっと覚えにくいなと思っていました。特にリストや文字列といった基本的なオブジェクトを操作する関数については迷うことが多いです(removeとか)。その上でsrfiは文字でなく番号でつけられているため、とても覚えにくいなという印象が強くなります(これ自体はGaucheのせいではないんですけど)。
Nonblocking Connect
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)))))))
- Shiro(2005/10/26 20:57:53 PDT): 私はそっち方面に明るくないので コアにこれを持たせる必要性がよくわからないのですが、 math.なんとか、みたいな拡張モジュールで持たせるぶんには構いません。 その場合、これだけじゃなくて使いまわしのきく数論アルゴリズムパッケージ、 みたいになってるといいですね。もし何かデザインして頂ければ本体に バンドルできるんじゃないかと思います。
- ひらっち: 拡張モジュールでもいいと思いますが、
できれば剰余付き累乗だけでも最初に乗っけてほしいです。
DH法やRSAのような公開鍵暗号は、この関数一つあれば
Schemeで実装できてしまいますから、
もし高速な実装ができれば実用上で意味があるのではないかと思います。
私も勉強中ですので、undocumented で pow-mod を math. 以下に入れて
そこから積上げてくってのがやりやすいかも。
例えばDH法自体は、以下のように pow-mod があれば簡潔に書けます。
(パラメータの生成はもうちょっと複雑)
ただ、pow-mod まで Scheme で書くと非常に遅くなるんです。
(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)))
- Shiro(2005/10/27 02:25:41 PDT):ふむ。こっそりmath.pow-modを作ってそっから色々 試してもらうのも手ですが、将来的にモジュールがあまり増え過ぎると目的の関数を 探すのが大変になるので、覚えやすい単位でグループ化できるものはしときたい、 という意図があります。例えばmath.modularとしてmodular arithmeticを実装する、 というのはどうでしょう。今すぐでなくても将来色々とそのモジュールに 追加してゆけそうな括りならば、とりあえず最初はpow-modだけを実装しておいて 徐々に便利そうな関数を増やしてゆく、というのでいいです。 私自身はあまり触ったことのない分野なのでそのへんの予想がつかないんで、 助言頂ければありがたいです。
- ひらっち:勉強中で助言というのもアレですが、整数論ではプリミティブは 少なめで、応用がいっぱいという印象です。 pow-mod を入れるのも、単純に計算コストがこの関数に 集中しているという理由からですし、 現状で不足している関数といえば pow-mod くらいかと思います。 将来の拡張を考えるのなら、数論/算術全体に対して math.arithmetic とかにした 方が良くないでしょうか。
Nonblocking Write
ソケットに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が特定の戻り値を返す、みたいな 方法が現実的な線かもしれません。条件がかかるのが醜いですが…
- なるほど。write-blockにPutzからコードをコピペして、生のfile port(バッファリングなし)という条件のときだけ、書き込んだバイト数を返すようにしてみました。EAGAINのときは0を返します。うまく動くようです。私にはこういう程度でいまのところ十分のようです。
Shiro: Port回りは0.9までに直さなくちゃならない項目の筆頭なので、 たぶん0.8.6後に本格的に取り組むことになると思います (srfi-68の進行も 横目で見てないとならないんですが)。そこで対応を考えたいと思います。
- ありがとうございます。期待しています。
any, every for gauche.collection
- (2004/12/20 04:25:50 PST) ねるWiki:ねる: gauche.collectionにany, everyもほしいです。
- leque(2006/09/13 22:26:58 PDT): filter-map や count も generic に扱えると嬉しいと思いました。こんな感じで collection.scm sequence.scm
after-gc-hook
- (2004/09/15 23:56:20 PDT) ねるWiki:ねる Scm_RegisterFinalizerをschemeからも使いたいです.
Shiro: これはそう簡単ではないんですよ。=> 議論はGauche:Schemeコードのファイナライザ
weak-hash-table
- (2004/09/15 23:56:20 PDT) ねるWiki:ねる weak-vectorだけだとちょっと不便なのであるとうれしいです.
- Shiro: 欲しいですね。単に開発の手間の問題で後回しになっています。
- ねるWiki:ねる: ああ、では、書いてみます。
export-all*
export-allする際に、頭が%のものはexportしないようなexport-all*が欲しいです。prefixが設定できればなおいいのですが、%固定で充分だと思います。今作っているモジュールのpublic/private数が62/3なので大変なことになってまして・・・。--hira(2004/03/17 02:35:42 PST)
- 参考 Scheme:!と? nakamuraさんとこ
- そのmoduleの先頭で以下のようなマクロを定義して、exportするものを明示的にこれでdefineすればいいんじゃないでしょうか。
(define-syntax define-public (syntax-rules () ((_ (f . args) . body) (begin (define (f . args) . body) (export f))) ((_ i v) (begin (define i v) (export i)))))
- Shiro: exportに関しては実装も含めてきれいな解決を探したいので、
当面はアドホックに対応して頂けますか。
- regexpを使う場合、exportが評価された後でそのモジュールにシンボルが 追加されると問題になります (モジュールは「閉じて」いないため、いつでも 新たなシンボルが追加され得ます)
- define-public方式はだいたいうまく動くんですが、define-class等別のマクロと 両立しないんですね。そういうのだけ明示的にexportを書くってので運用上は なんとかならなくはないんですが、システム標準にするのにはまだ抵抗があるって 感じです。
- アドホックなやつ置いておきますね。命名規則とスコープが結びついてるのはラクちんで良い感じです。hira
(define-macro (export-all-but% name) (define (filter-publics name) (define env (module-table (find-module name))) (define (public? key) (not (eq? (~ (symbol->string key) 0) #\%))) (filter public? (hash-table-keys env))) `(export ,@(filter-publics name)))
add-load-path
- skimu: 文字列を持っている変数を渡せたらうれしいです。
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