2014年1月31日金曜日

[OCaml]Unicodeライブラリ Camomile

今時の言語はUnicodeはサポートされているんだろうと思って、日本語の文字列の長さを調べてみたら、
utop[5]> String.length "日本語";;
- : int = 9
正しい値が返ってこない。バイト長を返している...
いろいろ調べてみると、OCamlでは外部ライブラリを使わないと、Unicodeとして扱えないようだった。
Stackover flowで、Camomileがお勧めされていたので、試してみた。

インストール

Camomileはopamでインストールできる。
~$ opam search camomile
Available packages for system:
camomile  0.8.5  A comprehensive Unicode library
zed         1.2  Abstract engine for text edition in OCaml
~$ opam install camomile
[NOTE] Package camomile is already installed (current version is 0.8.5).

おっと。いつのまにかインストールされていた。

ドキュメントの生成

.opamの中にアーカイブされたライブラリのソースがあるので、それを使おう。
~/src$ cp ~/.opam/packages.dev/camomile.0.8.5/camomile-0.8.5.tar.bz2 ./
~/src$ tar jxf camomile-0.8.5.tar.bz2
~/src$ cd camomile-0.8.5
~/src/camomile-0.8.5$ ./configure

config.status: WARNING:  'Makefile.in' seems to ignore the --datarootdir setting
という警告が出るが、ドキュメントを生成するだけなので放置する。
~/src/camomile-0.8.5$ make
~/src/camomile-0.8.5$ make dochtml

dochtmlディレクトリにドキュメントが生成される。
~/src/camomile-0.8.5$ cd dochtml
index.htmlを開けば良い。
~/src/camomile-0.8.5/dochtml$ iceweasel index.html

試してみる

utop[0]> open CamomileLibrary;;
utop[1]> let s = "日本語";;

val s : string = "日本語"
utop[2]> String.length s;;
- : int = 9
utop[3]> UTF8.length s;;
- : int = 3

正しい文字長である3が返った。

本当は XString.length を使いたかったのだけど、
string を xstring にする関数を見付けられなかった。
どう書くのだろう。

参考


2014年1月26日日曜日

[OCaml][Emacs]merlin での モジュール指定

Emacs + tuareg + merlin の開発環境で、複数モジュールからなるOCamlのプロジェクトで、Unbound module 〜 エラーが発生し、モジュールを参照するコード部分がエラーと判定されて、赤くなってしまった。
外部モジュールを認識しない場合、M-x merlin-use でモジュール名を指定すれば、認識するようになるが、プロジェクトに含まれるモジュールの場合は、.merlinファイルで、モジュールの場所を指定する。
これに対処するには、以下の内容の.merlinファイルをプロジェクトディレクトリに作成する。

以下は .merlinファイルの例

B _build
PKG core


B で モジュールのcmiファイルがあるディレクトリを指定する。
PKG で 使用する外部モジュールを指定する。

なお、インストールされている外部モジュールの名称は、以下のコマンドで確認できる。
$ ocamlfind list

参考


2014年1月25日土曜日

[OCaml][Emacs]tuareg の Unbound module Core エラー に対処する

OCamlのコードを書くときは、EmacsでTuareg + merlin を使っている。
エラーがあると、該当箇所が赤く表示されるので分かり易い。
Coreモジュールを使うコードでは、
図のように、Coreに関連するコード部分が赤く表示されて、
エラー扱いになってしまう。
Coreモジュールを読み込んでないようで、
Unbound module Core
とミニバッファにエラーメッセージが表示されてしまう。


これに対処し、Coreモジュールを認識させるには、
M-x merlin-use
で core を入力すれば良い。
しかし、解除方法は分からなかった。どこに設定が保存されているのだろう。
→ Emacsを再起動したら、初期化されるようだ。
毎回 merlin-use を実行するのが面倒なら、init.elに書いておく。

参考


2014年1月21日火曜日

[OCaml]グラフィックライブラリLablGtkを試してみる(2) - Canvasのサンプルを実行する

Canvasを使いたい。
ということでlablgtkのソースに含まれるexaplesディレクトリを調べてみると、あった!

$ cd lablgtk-2.18.0/examples/canvas
$ ls

canvas-arrowhead.ml  canvas-features.ml  canvas-primitives.ml  flower.png
canvas-curve.ml      canvas-fifteen.ml     canvas-richtext.ml    toroid.png

とりあえず、canvas-curve.mlを試してみる。
$ lablgtk2 canvas-curve.ml
File "canvas-curve.ml", line 21, characters 4-19:
Error: Unbound module GnoCanvas

GnoCanvasというモジュールが必要なようだ。
opamで探してみる。
$ opam search GnoCanvas
[ERROR] No packages found.
'opam search GnoCanvas' failed.

ない...
それでは、canvasだとどうかな?
$ opam search canvas
Available packages for system:
conf-gnomecanvas  --  Virtual package relying on a Gnomecanvas system installation.
vg                --  Declarative 2D vector graphics for OCaml

あった!
conf-gnomecanvas をインストールすれば良さそうだ。

$ opam install conf-gnomecanvas
〜略〜
[ERROR] The compilation of conf-gnomecanvas.2 failed.
Removing conf-gnomecanvas.2.
〜略〜
===== ERROR while installing conf-gnomecanvas.2 =====
# opam-version 1.1.0
# os           linux
# command      pkg-config libgnomecanvas-2.0
〜略〜

とエラーが出た。
メッセージを良く見ると、libgnomecanvas-2.0が必要なのかな?

$ dpkg --list | grep libgnome
ii  libgnome-keyring-common              3.4.1-1                            all          GNOME keyring services library - data files
ii  libgnome-keyring0:i386               3.4.1-1                            i386         GNOME keyring services library

確かにそんなライブラリはインストールしていない。

$ apt-cache search libgnomecanvas2
libgnomecanvas2-common - powerful object-oriented display engine - common files
libgnomecanvas2-dev - powerful object-oriented display engine - development files
libgnomecanvas2-doc - powerful object-oriented display engine - documentation files
libgnomecanvas2-0 - パワフルなオブジェクト指向表示エンジン - ランタイムファイル
libgnomecanvas2-dbg - パワフルなオブジェクト指向ディスプレイエンジン - デバッグシンボル
libgnomecanvasmm-2.6-1c2a - libgnomecanvas2 の C++ 版ラッパー (共有ライブラリ)
libgnomecanvasmm-2.6-dev - libgnomecanvas2 の C++ 版ラッパー (開発用ファイル)
libgnomecanvasmm-2.6-doc - libgnomecanvas2 の C++ 版ラッパー (ドキュメンテーション)

libgnomecanvas2-devをインストールする。
$ sudo apt-get install libgnomecanvas2-dev

再度、conf-gnomecanvasをインストールする。
$ opam install conf-gnomecanvas

今度は成功だ。
試してみる。
$ lablgtk2 canvas-curve.ml
zsh: command not found: lablgtk2

おや?lablgtk2コマンドがなくなった。
もう一回、lablgtkをインストールしよう。
$ opam install lablgtk2

インストール完了後、再度実行だ。
$ lablgtk2 canvas-curve.ml
File "canvas-curve.ml", line 1:
Error: Reference to undefined global `GnoCanvas'

うーむ。GnoCanvasが見えない(のか無いようだ)。
探してみる。

$ cd .opam
$ find ./ -name 'gno*'

./system/lib/lablgtk2/gnomeCanvas.ml
./system/lib/lablgtk2/gnoCanvas.mli
./system/lib/lablgtk2/gnoCanvas.cmx
./system/lib/lablgtk2/gnoDruid.mli
./system/lib/lablgtk2/gnoCanvas.cmi
./system/lib/lablgtk2/gnoCanvas.ml
./system/lib/lablgtk2/gnomeCanvas.cmi
./system/lib/lablgtk2/gnomeCanvas.cmx

ちゃんとファイルはあるなぁ。ライブラリパスの設定がまずいのか?
どう設定するのだろう。

lablgtk2のソースを見てみると、
$ lv `which lablgtk2`
〜略〜
    echo "Usage: lablgtk2 <options> <ocaml options> [script-file]"
    echo "  -thread   use the threaded version of the toplevel"
    echo "  -all      load all extensions"  ←◆これ
    echo "  -noinit   do not initialize gtk"
    echo "  -localdir use libraries in the same directory (before install)"
    echo "  -verbose  show actions executed"

おっと。-all が使えそうだ。

$ lablgtk2 -all canvas-curve.ml

やっと、動いたー!


Awesomeというタイル型のウィンドウマネージャを使っているので、余白が多いのかも。
他のウィンドウマネージャを使えば、相応のウィンドウサイズで表示されるはず。

[OCaml]グラフィックライブラリLablGtkを試してみる

調べてみたら、lablgtkというライブラリがあった。
OCamlではモジュールと呼ぶのかな?

LablGtk
LablGtk is an OCaml interface to GTK+ 1.2 and 2.x.

opamでインストールできる。
$ opam install lablgtk
〜依存パッケージと共にインストールされる。
$ rehash
(zshを使っているので。)
これで lablgtk2コマンドが使えるようになった。

.opamディレトリにサンプルコードがインストールされると思ったが、無かった。
では、ソースをダウンロードしよう。
$ cd ~/src
$ wget https://forge.ocamlcore.org/frs/download.php/1261/lablgtk-2.18.0.tar.gz

--2014-01-20 23:33:50--  https://forge.ocamlcore.org/frs/download.php/1261/lablgtk-2.18.0.tar.gz
forge.ocamlcore.org (forge.ocamlcore.org) をDNSに問いあわせています... 87.98.154.45
forge.ocamlcore.org (forge.ocamlcore.org)|87.98.154.45|:443 に接続しています... 接続しました。
証明書の所有者の名前とホスト名 `forge.ocamlcore.org' が一致しません

怒られた。うーむ。良くないなーと思いつつも、えい。
$ wget --no-check-certificate https://forge.ocamlcore.org/frs/download.php/1261/lablgtk-2.18.0.tar.gz
--no-check-certificate   サーバ証明書を検証しない
ダウンロードできた。
展開しよう。
$ tar zxf lablgtk-2.18.0.tar.gz
$ cd lablgtk-2.18.0/examples
$ ls

GL               csview.ml           events2.ml           label.ml           socket.ml
about.ml           curve.ml               expander.ml           link_button.ml       sourceview
accel_tree.ml           custom_list_generic.ml  fifteen.ml           lissajous.ml       spell.ml
action.ml           custom_tree.ml           filechooser.ml           nihongo.ml       spin.ml
assistant.ml           custom_tree_generic.ml  fixed_editor.ml           notebook.ml       test.xpm
assistant_tutorial.ml  dcalendar.ml           fixpoint.ml           panel           testdnd.ml
buttons.ml           dialog-thread.ml        gioredirect.ml           pixview.ml       testgtk.ml
calc.ml               drawing.ml           giotest.ml           pousse.ml       testthread.ml
calendar.ml           druid.ml               glade               progressbar.ml       text
canvas               editor.ml           gnome-fs-directory.png  radiobuttons.ml       timer.ml
cgets.ml           editor2.ml           gnome-fs-regular.png    rpn.ml           toolbar.ml
clist.ml           entry.ml               hello.ml               rsvg           tooltip.ml
combo.ml           entry2.ml           iconview.ml           runthread.ml       tree.ml
combobox.ml           entrycompletion.ml      image.ml               scrolledwin.ml       tree_model.ml
counter.ml           eventbox.ml           image256x256.rgb        signal_override.ml  tree_store.ml
cputs.ml           events.ml           kaimono.ml           slide_show.ml       tron.ml

いろいろあるなー。
手始めに、やっぱり hello.mlだよね。
$ lablgtk2 hello.ml
Hello World というラベルが付いたボタンのウィンドウが表示された。
ボタンを押すと、
Hello World
と文言を出力して終了した。

ソースを見ると、
$ cat hello.ml
(**************************************************************************)
(*    Lablgtk - Examples                                                  *)
(*                                                                        *)
(*    There is no specific licensing policy, but you may freely           *)
(*    take inspiration from the code, and copy parts of it in your        *)
(*    application.                                                        *)
(*                                                                        *)
(**************************************************************************)

(* $Id$ *)

open GMain

let window = GWindow.window ~border_width: 10 ()

let button = GButton.button ~label:"Hello World" ~packing: window#add ()

let main () =
  window#event#connect#delete
    ~callback:(fun _ -> prerr_endline "Delete event occured"; true);
  window#connect#destroy ~callback:Main.quit;
  button#connect#clicked ~callback:(fun () -> prerr_endline "Hello World");
  button#connect#clicked ~callback:window#destroy;
  window#show ();

ほー。簡単そうに見えるなぁ。
#で連鎖してメッセージ呼び出しできるのかな?

今日はここまでにしておこう。

2014年1月19日日曜日

[OCaml][Book]プログラミングの基礎 読了

プログラミングの基礎 (Computer Science Library) を読んだ。
SICPに関連するブログ徘徊していたら、あちこちでお勧めされていた書籍。
冬休み+αを利用して、一通り演習問題を解きつつ、読了。

最近読んだプログラミングの本の中では、一番楽しかった。
本書をきちんと読んでいれば、演習問題も簡単で、すいすい読み進める。
もっと早くこの本を読んでおけば良かった。

本書では、一冊を通して、メトロネットワーク最短経路問題を解くプログラムを作り、
その過程で、以下の内容が学べる(目次から抜粋)。
  • 基本的なデータ
  • 変数
  • 関数
  • 条件分岐
  • エラー
  • パターンマッチ
  • レコード
  • リスト
  • 再帰処理
  • ダイクストラのアルゴリズム(最短経路を求めるためのアルゴリズム)
  • 高階関数
  • 再帰の停止性の判定
  • 再帰的なデータ構造
  • 例外処理
  • モジュール
  • 逐次実行
  • 参照透過性
  • 副作用
使用言語は関数型言語であるOCamlを使う。
対象はプログラミングをしたことがない人向けということであるが、関数型言語を使ったことがない、知らないという人にもお勧め。
使用言語はOCamlであるが、HaskellやScalaでも役立つような、関数型言語での普遍的な内容を学べる。

関数型言語を始めたばかりだと、副作用がない処理を、どのように組み合せて実装するのか、良く分からないが、本書を順番に読み進めていくと、特に関数型をいうことを意識しなくても自然に実装できるようになってくる。
実際に、副作用については、本書の最後の方まで出てこない。
副作用がある処理は一切考えなくても、普通に処理を実装することが理解できる。

感想は以下の通り。
  • 副作用がない処理の実装に慣れてくると、副作用がある処理は不自然に感じてくる。
  • 強力な型チェックは、バグを減らすためにとても便利。
  • 再帰は自然な処理だ。
  • 関数型言語では、Howを実装するのではなく、Whatを実装する。
  • OCaml楽しい!

OCamlはHaskellと比べると、少し洗練さ足りない(泥臭い)感じがするのだけど、楽しく感じてしまう。何故なんだろう。
気に入ったので、OCamlで、いろいろプログラムを書いてみよう。