nekoie:log

nekoie:log

新しい文章はnekoieにあります。



scheme.vimとgosh_completions更新しました(Gauche-0.9対応その他)

srfi-62(S式コメント)への対応がより完璧になりました。

追記: 色々と問題が発覚したので、11/27に修正版を上げ直しました。

socketをノンブロッキングモードにしてはいけない

という事を思い知った。

speedygoshが大きいデータを扱おうとすると途中で切れてしまうのはこれが原因だった。直した。

Haskellのbracket

を会社で教えてもらったので、真似してみた。

(define (bracket before-thunk after-proc main-proc)
  (let1 args #f
    (dynamic-wind
      (lambda ()
        (receive r (before-thunk)
          (set! args r)))
      (lambda ()
        (apply main-proc args))
      (lambda ()
        (apply after-proc args)))))

以下のように使う(すごい適当)。

(bracket
  (lambda ()
    (values
      (open-input-file "in.txt")
      (open-output-file "out.txt")
      ))
  (lambda (in out)
    (close-input-port in)
    (close-output-port out)
    )
  (lambda (in out)
    ...)) ; 長い長い処理

素のdynamic-windと比べた利点

欠点

あとで気付いた、致命的な問題

irc用bot作成用モジュール書きました

※しばらく当分(2009/01/05 16:22:56 PST現在)は色々と修正したりする筈なので、安定したのを使いたい場合はまだ待っててください

scheme.vim更新しました(Gauche-0.8.14対応)

Gauche-0.8.14のインストールではまった

当初、「./libgauche.so: undefined reference to `___tls_get_addr'」というエラーが出てビルドできなかったが、どうにか解決した。

  1. Gauche内のgcのバージョンが上がった
  2. gc内では、スレッドの使い方を指定する定義として、「USE_COMPILER_TLS」が定義されたり、もしくは「USE_PTHREAD_SPECIFIC」が定義されたりする。通常は、どっちになるかは自動判定
  3. しかし、その自動判定の条件は「gccのバージョンが3.3以降か否か」(他にも色々な条件があるが割愛)だが、実はその判定では誤判定してしまう環境もあるっぽい
  4. とりあえずスレッド関係だという事は分かったので、Gaucheのconfigureの方で--disable-threadsすればビルドできるのは確認。でもそれだと当然スレッド使えない
  5. 手で明示的に「USE_PTHREAD_SPECIFIC」を使うようにしたらビルドできた

同様の環境の人が他にも居るかは分からないですが、もし同様の罠に引っかかったら、Gaucheのconfigure時に、以下のようにフラグをつけるといいです(gcだけにフラグを渡す方法は分からなかった)

export CFLAGS="-O2 -DUSE_PTHREAD_SPECIFIC"
./configure ...

Gauche用OOMパッチ

チャーチ数エミュレート

Arcからの挑戦

私は効率性のために妥協をして、チャーチ数を使わないことにした。[2]

を見て、ちょっと思い付いたので書いてみた。

(define-method object-apply ((num <integer>) proc . args)
  (cond
    ;; マイナス値は今回はエラーにしたが、
    ;; マイナス値の時も0とみなしてもいいかも
    ((< num 0) (error "minus number found"))
    ((= num 0) (apply values args))
    (else
      ;; 本当に真面目に使うつもりなら、
      ;; ここは末尾再帰に直すべき
      (receive r (apply proc args)
        (apply object-apply (- num 1) proc r)))))
(3 cdr '(0 1 2 3 4)) => (3 4)
(define (baibain x)
  (append x x))
(4 baibain '(1 2))
=> (1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
    1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)

これが役に立つのか、と言われると困るけど。

scheme.vim更新しました

Gauche:$を見て思った事

書いてみた。

個人的要望

gauche-package install --clean URL ではまる

scheme.vim更新しました(2007/10/19 08:28:02 PDT)

implicit forceに関する妄想

http://d.hatena.ne.jp/ranekov/20070923#c1190540213 でもらったコメントを見て考えてみた。

gauche.gongのkoguroさんのデモがウェブでも公開されたので、改めて見直した

speedygoshのバグを発見してしまった(修正済/バージョン上がりました)

gauche.night参加してきました

すごかった。 皆様どうもお疲れ様でした。

とりあえず印象に残った事を。

とにかく濃かったです。 参加して良かった。

継続サーバについてあれこれ思う事をメモ

gemma:継続サーバを見てみました。

なるほど、セッションが明示的に生成される毎に、継続プロセスも明示的に生成する手があったんですね。

昔、自分もCGI等で使える、lightweightな継続保持システムが欲しくなって、ちょっと試しに作ろうとしてみたのですが、「継続(やlambda)のシリアライズ」と「入出力の抽象化」の二つの部分が上手くいかず諦めました。 (Kahuaは、常駐動作するので継続をシリアライズする必要は無いし、入出力はSXMLで上手く抽象化されてます。)

しかし、よく考えてみると、継続保持が必要な状況というのは大抵、管理画面CGIやら登録制ウェブサービスやらネットワークゲームやらの、「事前にログイン(またはセッションに相当する何か)を行ってから本処理を行う」用途が大部分のように思えます、自分には。 (と言うか、ログインとか無しに継続保持動作をサーバにやらせられる状態は、ウェブクローラからのアクセス等によってDoSっぽい事になったりしそうで、ちょっとまずそうです。) なら、それに特化してもいいかもしれない、と気付きました。

具体的には、ログイン(か新規セッション作成)される毎に、gemma:継続サーバのように、ログインidやセッションidをkeyにした継続プロセスを生成する(つまり、1クライアントにつき1プロセスを完全に割り当てる形になる)、セッション部分の管理までも含めた、セッション付き継続保持システム用モジュール。

これなら、ログイン(セッション)単位での管理になるので、一定時間アクセスがなければタイムアウトして継続を破棄するような実装でも(データ保存さえちゃんとできているなら)文句は言われないし、継続の破棄タイミング=タイムアウト(またはログアウト)という事で分かりやすいし、実装も割と簡単そうです。 (多分、自分の書いたspeedygoshsocket.server(今中途半端な状態。また今度ちゃんと作り直す予定)の中間ぐらいになりそうに思えます。)

その内作りたいです。 (多分、socket.serverの改良版の次ぐらいに作りそう。そっちを先に作り直した方が作るの楽そうだから。)

ですが、他の人も作りたかったら、どうぞ作ってください。 (その時には、よかったら自分にも使わせてほしいです。)

はまった事

両方とも同じだと思ってたら、ひどい目にあった。

これはちょっと、リファレンスに書いといてほしい……。

speedygoshを作っていて見付けた、Gauche内部に手を入れないと越えられそうにない壁

とりあえず三つ。

  1. sys-putenvがメモリリークする(とりあえず(gc)しても回収されないところまでは確認)
  2. sys-system実行時のstdout/stderrの変更(本質的には、(standard-*-port)の変更のサポート)
  3. (exit n)が実行された時に、nの値に応じた処理を終了直前に行いたい(atexitに似ているが、その時に終了値も参照したい。単なるatexit的挙動だけならdynamic-windで可能だと思う)

speedygoshとしては「サーバプロセス側もCで書いて、libgauche経由でスクリプトを評価させる」方法で、この三つは解決するし、そうすればGauche以外のスクリプト言語に移植しやすくなるというおまけもつく。

しかし、それに今手を出すのはちょっと微妙にハードだ。

一番目(と二番目の一部)に関しては、Gauche内部で**environ的なテーブルを保持して、普段のsys-getenv/putenvではそのテーブルだけを操作するようにし、sys-systemやexec類の実行前にのみ(もしテーブルが変更されているなら)putenv等で再設定するようにすれば解決すると思う。 環境変数をlistとして扱えるようになるというメリットもある。 おそらく他のスクリプト言語もそうしてると思う、多分。 これの問題点は、putenvをサポートしていない環境をどうするかという部分ぐらいだと思う。

ソースをパッと見た感じだけだと、これはそんなに難しくなさそうだから、どうしても必要になりそうなら、自分でパッチを書いてしまおう。

二番目の問題は、ちゃんとは見てはいないがおそらく、変更処理自体は可能だと思う。 ここで問題になりそうなのは、例えば、(standard-output-port)がGaucheで書かれたvportに変更された後にsys-systemやexec類が実行された場合。

sys-systemの時は、適当にpipeや一時ファイルをstdout/stderrに割り当ててから実行し、完了してから、この場合は(standard-output-port)よりも(current-output-port)に流し込んだ方が親切なんだろうか……これはちょっと微妙そうな問題だ。 正直、その辺を気にするような人なら素直にgauche.processを使うと思うから、どっちでもokそうな気はする。 exec類だった時は、(standard-output-port)が普通の*FILEだったらそれを採用、vportとかだったら/dev/nullにする、とかにすれば、一応いけそうな気はする。 それか、単にvportを設定しようとした時はエラーにするか。

ここはちょっと仕様が微妙な事になりそうだ。 諦めた方がいい?

最後の三番目の仕様は、speedygosh以外には需要なさそう。

そこまで考えると、やっぱり一番真っ当なのは「サーバプロセスもCで書く」という事になる。

自分の見積りでは、自分のCの実力でサーバプロセスをCで書いてとりあえず動く状態にまで持っていくのに、40時間の空き時間は欲しい感じだ。 普段の仕事と他の遊びもあるので、日数にして大体20日~一ヶ月ぐらい? これは微妙だ。 どうしよう。

speedygosh

speedycgiのgosh版を開発中。未実装部分がまだ多い。

極簡単なwilikiのスパイダー避け

Shiroさんの2006/09/25の日記で、履歴差分をスパイダロボットがもっていって負荷が高くなる、という問題が出ていたので、とりあえず通常のスパイダロボットならformボタンは辿らない、という前提で、編集と編集履歴のリンクをボタン化してみた。

ただ、この方法だと、編集履歴一覧ページは元のままなので、既にさんざんスパイダロボットにもってかれた後だと意味なさそうだけど。

編集履歴一覧ページの一覧リンクもボタン化すればokそうだけど、見栄えが悪くなりそうなのでやってない。

真面目に実装するなら、User-Agentを見て判断するしかなさそうだが、それも微妙な問題が色々出てきそうだ。

正規乱数の取得

;;; - http://ja.wikipedia.org/wiki/%E4%B9%B1%E6%95%B0
;;; -- ボックス=ミューラー法による実装

(use math.mt-random)
(use math.const)

(define *mt* #f)
(define (make-mt!)
  (unless *mt*
    (receive (epoch micro) (sys-gettimeofday)
      (set! *mt* (make <mersenne-twister>
                       :seed (+ epoch micro (sys-getpid)))))))


(define (normal-distribution-random . keywords)
  (make-mt!)
  ;; note: この関数は二つの正規乱数を多値で返す。
  ;;       (一つしか必要ない場合は片方は適当に捨てれば良い)
  ;;       キーワード引数は以下の通り。
  (let-keywords* keywords (
                           (sigma 1) ; 分散度を指定。
                           ;; sigmaが大きいと平均的に分散し、
                           ;; sigmaが0に近いとmu近辺しか出なくなる。
                           (sigma-plus #f) ; +方向と-方向で、sigmaの値を
                           (sigma-minus #f) ; 変更したい場合に個別に指定する。
                           ;; 尚、sigma-plusかsigma-minusにマイナスの値を
                           ;; 指定する事で、半分に折り返した正規分布を
                           ;; 作る事も可能。
                           (mu 0) ; 一番出やすい期待値(平均の中央)を指定。
                           (clamp-min :min #f) ; 結果をclampする場合に指定
                           (clamp-max :max #f) ; 結果をclampする場合に指定
                           )
    ;; 「(0, 1]」の乱数を二つ用意する
    (define (get-r)
      (- 1 (mt-random-real0 *mt*)))
    (let ((alpha (get-r))
          (beta (get-r)))
      ;; 以下の計算を行う事で、二つの相関の無い正規乱数が得られる。
      ;; ((-2 * log(α))^0.5) * sin(2 * PI * β)
      ;; ((-2 * log(α))^0.5) * cos(2 * PI * β)
      ;; 左辺(result-alpha-part)と、sin/cosの中味(result-beta-part)を先に求める
      (let ((result-alpha-part (expt
                                 (* -2 (log alpha))
                                 0.5))
            (result-beta-part (* 2 pi beta)))
        ;; 二つの正規乱数を得る。
        (let ((result1 (* result-alpha-part (sin result-beta-part)))
              (result2 (* result-alpha-part (cos result-beta-part))))
          ;; 上記二つの正規乱数を加工して返す
          (define (post-process r)
            (clamp
              (+ mu
                 (* r (or
                        (if (positive? r) sigma-plus sigma-minus)
                        sigma)))
              clamp-min
              clamp-max))
          (values (post-process result1) (post-process result2)))))))

これで、それっぽい様々なデータを捏造する事が出来る。

間違いや改良点とかあれば、教えてください。

使いたいと思った方は、適当に持っていってください。


tips

www.cgi.dispatch-tir


某所の何かを見てTypeKeyを使いたくなったので、突発的にTypeKey認証モジュールを作りました(と言うか、移植しました、pythonのTypeKeyモジュールを)。



CGI書き男から見たgaucheその二(というか要望)

www.cgiモジュールに、ces判別用のinput hiddenタグの文字列から、送信されたフォーム内容全体のcesを判定する機能が欲しいです。

困った事

CGI書き男から見たgaucheその一

ええっと、一般的に、ソレっぽいウェブアプリを書く場合、 以下の二点のサポートが重要な気がします。

前者は、要するに、素のスクリプトを毎回起動しているのでは、遅くて負荷もかかって、

とてもやっていられない、という事で、 大体三パターンのアプローチが取られている気がします(後述)。 gaucheでは一応httpd.scmがありますけど、自分としてはプロセスを永続化できる SpeedyCGI のような仕組があると自分がとても嬉しい気がします。

後者は、gaucheではndbm, gdbmがサポートされてますけど、最近のソレっぽい事を 始めようとか思う人が既に使ってたりして慣れてるのはやっぱり、 postgresとmysqlでしょう。

高速起動の三パターン

mysqlサポート

とりあえず、自分でも、必要最低限使えるレベルの、 mysqlコマンドを叩くモジュール を作ってみました。 そして、その ちょっとした動作テスト 。


Last modified : 2012/02/02 11:53:43 UTC