OCamlでWebアプリケー
ションを作るn個の方法
@mzp/ ocaml-nagoya
13年8月24日土曜日
自己紹介
•Twitter: @mzp
•名古屋で社内SEやってます
•ステッカー配布中
13年8月24日土曜日
Webサービスを作りたい
•今どきはローカルにインストールする
アプリケーションは流行らない(個人の
見解です)
•OCamlでもWebサービスを作りたい
13年8月24日土曜日
サーバの準備が必要
ミドルウェアを準備しないといけない
• Webサーバ(例: Apache)
• DBサーバ(例: PostgreSQL)
• その他(ログ監視、死活監視、...)
13年8月24日土曜日
サーバの準備が必要
ミドルウェアを準備しないといけない
• Webサーバ(例: Apache)
• DBサーバ(例: PostgreSQL)
• その他(ログ監視、死活監視、...)
→ 面倒くさい!
13年8月24日土曜日
準備するだけじゃない
•デプロイの自動化
•できればホットデプロイもしたい
•セキュアな設定 & バージョンアップ
•ユーザ数が増えたら増設
13年8月24日土曜日
準備するだけじゃない
•デプロイの自動化
•できればホットデプロイもしたい
•セキュアな設定 & バージョンアップ
•ユーザ数が増えたら増設
→ 面倒くさい!!
13年8月24日土曜日
Herokuを使いましょう
www.heroku.com より
13年8月24日土曜日
Herokuを使いましょう
www.heroku.com より
→ 意訳: インフラなしでアプリが作れます
13年8月24日土曜日
Herokuの特徴
簡単なデプロイ
git pushするだけでデプロイ可能
$ git push heroku master
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 293 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
-----> Fetching custom git buildpack... done
(snip)
-----> Compiled slug size: 66.2MB
-----> Launching... done, v11
http://buildpack-ocaml-hello.herokuapp.com deployed to Heroku
To git@heroku.com:buildpack-ocaml-hello.git
b810c68..03d7b87 master -> master
13年8月24日土曜日
Herokuの特徴
大量のアドオン
13年8月24日土曜日
Herokuの特徴
対応している環境
•Ruby
•Node.js
•Clojure
•Pyhton
•Java
•Gradle
•Grails
•Scala
•Play
13年8月24日土曜日
Herokuの特徴
対応している環境
•Ruby
•Node.js
•Clojure
•Pyhton
•Java
•Gradle
•Grails
•Scala
•Play
→ あれ...?
13年8月24日土曜日
Herokuの特徴
BuildPackで拡張できる
•C
•Common Lisp
•Dart
•Erlang
•Emacs
•Haskell
•Go
•Opa
•Perl
...などなど
13年8月24日土曜日
Herokuの特徴
BuildPackで拡張できる
•C
•Common Lisp
•Dart
•Erlang
•Emacs
•Haskell
•Go
•Opa
•Perl
...などなど
???
13年8月24日土曜日
本日の発表の趣旨
Buildpackを使って、HerokuでOCaml
を動かせるようにしました。
13年8月24日土曜日
Buildpackの仕組み
configure・
Makefile
ランタイム
コンパイラ
ソースコード
configure・
Makefile
ランタイム ライブラリ
実行ファイル
ビルド用
スクリプト
Buildpack-ocaml
1. デプロイ時 2. 実行時
・依存ライブラリのインストール
・実行ファイルのビルド
コンパイラ
ビルド用
スクリプト
ソースコード
13年8月24日土曜日
利用できるフレームワーク
1. Unixモジュール
2. ocamlnet
3. eliom
4. CamlGI
13年8月24日土曜日
利用できるフレームワーク
1. Unixモジュール
2. ocamlnet
3. eliom
4. CamlGI 21世紀にもなって、CGIはちょっと...
13年8月24日土曜日
利用できるフレームワーク
1. Unixモジュール
•Heroku上で動作させるには、Httpサ
ーバが必要
•OCaml標準のモジュール
• Socketの生成等ができる
•これができる = ほぼ全てのフレームワ
ークが使える
13年8月24日土曜日
サンプルコード
open Unix
(* 適当なHttpレスポンスを返す *)
let f _ out =
  output_string out "HTTP/1.0 200 OKnnhello,world"
(* Unixモジュールを使ってサーバを作る *)
let _ =
  let port =
    int_of_string Sys.argv.(1)
  in
  establish_server f
(ADDR_INET (inet_addr_of_string "0.0.0.0",
port))
13年8月24日土曜日
利用できるフレームワーク
2. Ocamlnet
•Ocamlっで公式ページに書いてあった
•いくつかのプロトコル(http, mail, cgi,
and etc)をサポートしているライブラ
リ
•Httpサーバを作るライブラリも入って
いる(Nethttpd)
13年8月24日土曜日
opamからのインストール
Buildpackには標準ライブラリしか入っ
ていない
• ocamlnetは含まれていない
• デプロイ時にインストールする必要がある
#!/usr/bin/env bash
opam install -y ocamlnet
./configure
13年8月24日土曜日
サンプルコード
open Printf
let generate (cgi : Netcgi.cgi_activation) =
(* A Netcgi-based content provider *)
cgi # set_header
~cache:`No_cache
~content_type:"text/html; charset="iso-8859-1""
();
let data =
"<html><h1>hi</h1></html>" in
cgi # output # output_string data;
cgi # output # commit_work();
let on_request notification =
printf "Received HTTP requestn";
flush stdout;
( try
let env =
notification # environment in
let cgi =
Netcgi_common.cgi_with_args
(new Netcgi_common.cgi)
(env :> Netcgi.cgi_environment)
Netcgi.buffered_transactional_outtype
env#input_channel
(fun _ _ _ -> `Automatic) in
generate cgi;
with e ->
printf "Uncaught exception: %s
n" (Printexc.to_string e);
flush stdout
);
notification # schedule_finish()
let start port =
printf "Listening on port %dn" port;
flush stdout;
let ues = Unixqueue.create_unix_event_system () in
let opts = { Uq_engines.default_listen_options with
Uq_engines.lstn_reuseaddr = true } in
let lstn_engine =
Uq_engines.listener
(`Socket(`Sock_inet(Unix.SOCK_STREAM,
Unix.inet_addr_any, port) ,opts)) ues in
Uq_engines.when_state ~is_done:(accept ues)
lstn_engine;
(* Start the main event loop. *)
Unixqueue.run ues
13年8月24日土曜日
サンプルコード
open Printf
let generate (cgi : Netcgi.cgi_activation) =
(* A Netcgi-based content provider *)
cgi # set_header
~cache:`No_cache
~content_type:"text/html; charset="iso-8859-1""
();
let data =
"<html><h1>hi</h1></html>" in
cgi # output # output_string data;
cgi # output # commit_work();
let on_request notification =
printf "Received HTTP requestn";
flush stdout;
( try
let env =
notification # environment in
let cgi =
Netcgi_common.cgi_with_args
(new Netcgi_common.cgi)
(env :> Netcgi.cgi_environment)
Netcgi.buffered_transactional_outtype
env#input_channel
(fun _ _ _ -> `Automatic) in
generate cgi;
with e ->
printf "Uncaught exception: %s
n" (Printexc.to_string e);
flush stdout
);
notification # schedule_finish()
let start port =
printf "Listening on port %dn" port;
flush stdout;
let ues = Unixqueue.create_unix_event_system () in
let opts = { Uq_engines.default_listen_options with
Uq_engines.lstn_reuseaddr = true } in
let lstn_engine =
Uq_engines.listener
(`Socket(`Sock_inet(Unix.SOCK_STREAM,
Unix.inet_addr_any, port) ,opts)) ues in
Uq_engines.when_state ~is_done:(accept ues)
lstn_engine;
(* Start the main event loop. *)
Unixqueue.run ues
長いので、ocamlnetの
サンプル見てください...
13年8月24日土曜日
利用できるフレームワーク
3. Eliom/Ocsigen
ocsigen.org より
13年8月24日土曜日
利用できるフレームワーク
3. Eliom/Ocsigen
→ 意訳:
ocsigen.org より
13年8月24日土曜日
利用できるフレームワーク
3. Eliom/Ocsigen
Webアプリケーションをシンプル
かつ安全に作れます!!
→ 意訳:
ocsigen.org より
13年8月24日土曜日
利用できるフレームワーク
3. Eliom/Ocsigen
Webアプリケーションをシンプル
かつ安全に作れます!!
→ 意訳:
ocsigen.org より
13年8月24日土曜日
Eliomの特徴
1. 型安全なロジック
•処理をOCamlで書ける(= サービス)
•Lwtが使える
• 非同期処理をモナディックに書ける
let () =
  Hello_app.register ~service
    (fun () () ->
      Lwt.return html)
13年8月24日土曜日
Eliomの特徴
2. 型安全なHTML
•曰く functional HTML5
•validでないHTML5は型エラーになる
•当然、HTMLはすべてOCamlで書く
type (‘a,’b) plus = ‘a * ‘a list -> ‘b
val table : ([< `Tr], [> `Table]) plus
例: <table>の型(一部略)
<table>の子に<tr>が1個以上ないと、型エラー
13年8月24日土曜日
Eliomの特徴
3. 型安全なJavascript
•js_of_ocamlによるJavascriptの生成
• OCamlの型チェックの恩恵が受けれる
• 素のJavascriptより最適化が効く
Dom_html.window##alert (Js.string "")
例: window.alertの呼び出し
13年8月24日土曜日
Eliomの特徴
4. Ajaxモナド
•非同期呼び出し(Ajax)にはLwtが使える
• モナディックにAjaxが扱える!
•他のAltJSにはない特徴
lwt x =
Eliom_client.call_caml_service ~service:a_service ()
in
lwt y =
Eliom_client.call_caml_service ~service:b_service ()
in
return (x + y)
例: a_serviceとb_serviceの非同期呼び出し
13年8月24日土曜日
Eliomの特徴
5. 型安全なSQL
Camlp4による拡張で、SQLをOCaml内
に埋め込める
let table = <:table< users (
login text NOT NULL,
password text NOT NULL
) >>
let find name =
(get_db () >>= fun dbh ->
Lwt_Query.view dbh
<:view< {password = user_.password} |
user_ in $table$;
user_.login = $string:name$; >>)
例: テーブル定義とクエリの発行
13年8月24日土曜日
Eliomの特徴
6. イベントハンドラ
その要素で発生しないイベントはバイン
ドできない
let dom =
of_form %task_form
in
on_submits dom begin fun e _ ->
...
例: <form/>のsubmitイベントへのハンドラ設定
13年8月24日土曜日
Eliomの特徴
7. サービスとの連携
•変なサービスを呼んでいないことを型
検査で保証できる
• サービスの存在の有無
• 引数の数、型
post_form ~service:done_service
(fun name-> [ int_input ~name ();
    sumbit_button ()])
コード例: done_serviceを呼び出す<form/>
13年8月24日土曜日
実例
TODOアプリケーション
•Buildpack-ocamlのデモ用に作ったア
プリケーション
• 無駄にAjaxを使っている
buildpack-ocaml-todo.herokuapp.com
13年8月24日土曜日
実例
OCaml◉Scope
•型によるOCaml APIの検索
ocamloscope.herokuapp.com
13年8月24日土曜日
より詳しい内容について
•全ソースコード(含む: サンプルコード)
github.com/heroku-buildpack-ocaml
•Buildpack-OCamlチュートリアル
その1: mzp.hatenablog.com/entry/2013/06/08/002630
その2: mzp.hatenablog.com/entry/2013/06/08/003029
•Eliomチュートリアル
ocsigen.org/tutorial/intro
13年8月24日土曜日
まとめ
•OCamlでWebアプリケーションが作り
たい
•Herokuで動かせるようにしました
•Eliomたのしい
13年8月24日土曜日

OCamlでWebアプリケーションを作るn個の方法