OCatraをLwt使うようにした

OCatraをいろいろ直したり、ベンチマークとってみたり - komamitsu.log で作っていたOCamlのおもちゃ的Webサーバー OCatraをLwtを使うように修正してみた。

1st 2nd 3rd 4th Ave.
OCatra (byte) 4238 4424 4299 4285 4311
OCatra (opt) 11806 12384 12381 12063 12158

bytecode版で1.5倍程度、native版で3倍程度高速になってうれしい。

nginxもついでに測ってみたのだけど、nginxのほうが倍近く速くて悔しい...

OPAMでインストールしたパッケージがocamlfindで見つからない件

OPAMいいですね。

http://d.hatena.ne.jp/wistery_k/20120909/1347164530 の記事を見て使い始めましたが、道具としてのOCamlが何かの壁を乗り越えそうな感じがしてます。

で、使っていて、たまにocamlfind -listの中にopamでインストールしたパッケージが出てこないことに気がつきました。

eval `opam config -env` でパス周りの設定を通しているので、こいつは .xxshrc辺りに書いておいてあげる必要がありそうです。


あと本題と関係ないけど、shell/opam_completion.sh とかを読み込んでおくと auto-completeが効くのでさらに便利。


追記(2012-10-08)

https://github.com/OCamlPro/opam に普通に載ってたわ...

OCatraをいろいろ直したり、ベンチマークとってみたり

komamitsu/OCatra · GitHub のkeepaliveまわりのバグとかを直したり、モジュール名を変更したりしました。

Eventモジュールを使ってすっきり書いた方が良さげだなぁとか思っているのですが、現状そんなにややこしい制御をしていないので、まぁいいかと。

あとついでに、thin上でSinatraを動かしたやつと、abでrpsを比べてみました (-c 200 -n 4000)。

1st 2nd 3rd 4th Ave. σ
OCatra (byte) 3089 3197 1761 3415 2865 748
OCatra (opt) 4288 1809 6120 3920 4036 1768
Sinatra + thin 1561 1613 1595 1557 1581 27

bytecode版とnative版でともにSinatra + thinよりも速いのですが、測定値にばらつきがありました。99%のリクエストは一瞬なんですが、1%未満でレスポンスが遅くなるみたい。ちょっと気になるな〜

OCatraを短くかけるように修正

SinatraっぽいOCatraを書いてみた - komamitsu.log で作ったOCatraですが、もうちょっとすっきり書けるように修正。

open Ocatra
open HttpCommon
open HttpCommon.HttpContent

let _ =
  get "/" (fun r -> say (TextPlain "Hello, World (GET)") ());

  post "/" (fun r -> say (TextPlain "Hello, World (POST)") ());

  get "/givemeyournameandage" (fun r ->
    say (
      TextHtml (
        "<html><head><title>hello " ^ r ++> "name" ^ "</title></head>" ^
        "<body><h3>you are " ^ r ++> "age" ^ " years old.</h3></body></html>")
    ) ()
  );

  run ()

SinatraっぽいOCatraを書いてみた

先日、やっつけのWebサーバーを書く際にRubySinatraで書いてみたのですが、「簡単に書けて良いな〜」と思ったので、OCamlでもそれっぽいものを適当に作ってみました。

komamitsu/OCatra · GitHub

現状はこんな感じでかけます:

open Ocatra
open HttpCommon
open HttpRequest
open HttpResponse

let _ =
  get "/" (fun req ->
    create_response (Some (HttpContent.TextPlain "Hello, World (GET)")) ()
  );

  post "/" (fun req ->
    create_response (Some (HttpContent.TextPlain "Hello, World (POST)")) ()
  );

  get "/givemeyournameandage" (fun req ->
    let name = HttpParam.find req.param "name" in
    let age = HttpParam.find req.param "age" in
    create_response (Some (
      HttpContent.TextHtml (
        "<html><head><title>hello " ^ name ^ "</title></head>" ^
        "<body><h3>you are " ^ age ^ " years old.</h3></body></html>")
    )) ()
  );

  run ()

「それっぽい感じで書けそうかな?」というのを確認した段階なので、肝心の「短くかけるか?」というのはあまり追求してない... 後で暇になったら頑張ろうかなと。

あと、ソースコードの配置とかMakefileとかSignature切ってないとかが、やっつけ感溢れるというか適当なので、これも暇になったら頑張りたい。

あと、OCamlのライブラリ依存を何とかするのが面倒で苦手なので、品質よりも簡単に使えること(できるだけ標準で用意されている環境で使いたい)優先で、HTTPサーバー的なところは自前で実装しています。この辺も結構適当にやってるので暇になったら頑張りたい。

いまさらのN Queen問題

最近、Scalaのコップ本を読んでいるのですが、例題でN Queen問題が出ていて、結構すっきり書かれていてへぇ〜って思いました。

そういえば、N Queen問題は試したことが無かったのと、このところコードをあまり書いていないような気がしたので、気分転換にOCamlで書いてみました。

結果はこんなかんじ

パーセプトロンの練習

最近、機械学習に興味を持ち始めていて、SVMを実装してみようと思ったら、挫折したのでやはり段階を踏むべきであろうということでパーセプトロンから試してみた。

komamitsu/ocaml-perceptron · GitHub

  • perceptron.ml
let ($) f g = f g

let print x =
  Hashtbl.iter (fun k v -> Printf.printf "%s => %d    " k v) x;
  print_newline ()

let inner_prod w x =
  Hashtbl.fold (fun wk wv a -> a + wv * (Hashtbl.find x wk)) w 0

let classify w x =
  if inner_prod w x >= 0 then 1 else -1

let learn w x y =
  if classify w x != y then
    Hashtbl.iter
    (fun xk xv ->
      let wv = Hashtbl.find w xk in
      Hashtbl.replace w xk $ wv + xv * y) x

let learn_all n w set_of_x_y =
  for i = 1 to n do
    List.iter (fun (x, y) -> learn w x y) set_of_x_y 
  done;
  w

これがパーセプトロンで学習したり分類したりするもので、何というか手順をそのままコードに落としただけ。

  • sample.ml
(* 
 * ocamlc -c perceptron.ml && ocaml perceptron.cmo sample.ml
 *)
let ($) f g = f g

let vec_of_assoc assoc =
  List.fold_left (fun w (k, v) -> Hashtbl.replace w k v; w) (Hashtbl.create 4) assoc 

let train_src =
  List.rev $
    List.fold_left
      (fun train_src (assoc, y) ->
        let x = vec_of_assoc assoc in
        (x, y)::train_src) [] [
          ([("R", 255); ("G",   0); ("B",   0); ("bias", 1)], 1);
          ([("R",   0); ("G", 255); ("B", 255); ("bias", 1)], -1);
          ([("R",   0); ("G", 255); ("B",   0); ("bias", 1)], -1);
          ([("R", 255); ("G",   0); ("B", 255); ("bias", 1)], 1);
          ([("R",   0); ("G",   0); ("B", 255); ("bias", 1)], -1);
          ([("R", 255); ("G", 255); ("B",   0); ("bias", 1)], 1);
        ]

let print_result x =
  let s = if x = 1 then "warm" else "cool" in
  print_endline s

let _ =
  let init = vec_of_assoc [("R", 0); ("G", 0); ("B", 0); ("bias", 1)] in
  let w = Perceptron.learn_all 10 init train_src in
  Perceptron.print w;
  let x = vec_of_assoc [("R", 200); ("G", 100); ("B", 100); ("bias", 1)] in
  print_result $ Perceptron.classify w x;
  let x = vec_of_assoc [("R", 100); ("G", 200); ("B", 200); ("bias", 1)] in
  print_result $ Perceptron.classify w x

で、こちらがそれを利用するサンプルで、機械学習超入門III 〜機械学習の基礎、パーセプトロンを30分で作って学ぶ〜 - EchizenBlog-Zweiの暖色・寒色の例を使わせて頂きました。

実行するとこんな感じに。

komamitsu@carrot:~/lab/ocaml/perceptron$ ocamlc -c perceptron.ml && ocaml perceptron.cmo sample.ml
bias => 0    B => -255    R => 255    G => -255
warm
cool

それはそうと、OCamlでHashtblを簡単に構築できるリテラルPerlとかRubyみたいやつ)が欲しいなぁと思いました。camlp4を使った何かがあるのかなぁ。